Next: Casting Structs, Previous: Integral Unions, Up: Structs [Contents][Index]
Sometimes a field in a struct is optional, i.e. it exists or not depending on some criteria. A good example of this is the “extended header” in a MP3 id3v2 tag. From the specification:
The second bit (bit 6) indicates whether or not the header is followed by an extended header. The extended header is described in section 3.2. A set bit indicates the presence of an extended header.
In order to express this in a Poke struct type, we could of course use an union, like:
type ID3V2_Tag = struct { ID3V2_Hdr hdr; union { ID3V2_Ext_Hdr hdr : hdr.extended_hdr_present; struct {}; } ext; … }
That’s it, we use an union with an empty alternative. However, this
approach has two problems. First, it is a bit cumbersome to write and
it becomes necessary to introduce an intermediate named field like
ext
above. Second, and most importantly, the constraint
expression in the union alternative is evaluated only once the
alternative has been already decoded.
Therefore Poke provides a more convenient way to denote this:
type ID3V2_Tag = struct { ID3V2_Hdr hdr; if (hdr.extended_hdr_present) IDV2_Ext_Hdr ext_hdr; … }
In the example above ext_hdr
will be decoded only if
hdr.extended_hdr_present
is true, which is what we want.
Sometimes, however, we really need to decode a field to decide whether it is present or absent in the final struct. In these cases, we can use a suffix syntax:
type ID3V2_Tag = struct { ID3V2_Hdr hdr; IDV2_Ext_Hdr ext_hdr if hdr.extended_hdr_present && ext_hdr.invisible; … }
Note how in this example the field ext_hdr
can appear itself in
the conditional expression.
If both a constraint and a suffix optional field expression are specified, the second should follow the first.
One important characteristic of optional fields with suffix expressions to keep in mind is that they are always constructed or mapped, even when they are omitted. This is because, generally speaking, the value of an optional field may be necessary in order to determine whether the optional field is present or not.
This may result on unexpected results for the unaware pokist, like in the example below:
struct { Header hdr; byte[hdr.len - hdr.padding] data if hdr.len >= hdr.padding; }
where the array index may underflow if hdr.len
is less or equal
than hdr.padding
.
The obvious solution for this problem is to use a prefix conditional expression instead.
For obvious reasons, optional fields are not allowed in unions.
Next: Casting Structs, Previous: Integral Unions, Up: Structs [Contents][Index]