In a library I'm working with I found a structure like this:
typedef struct {
uint16_t id;
uint16_t len;
union {
uint8_t data[0];
uint16_t data16[0];
uint32_t data32[0];
}
} packet_t;
So this is a packet with flexible-lengthed data, with an access to each of the word lengths.
But the standard says an object cannot have zero size, so compiling this raises a warning ("ISO C forbids zero-size array").
I compile the code in gcc so this zero-sized array hack will just do fine thanks to its extension. But is there any way I can be really "pedantic" about this? Flexible Array Member didn't help because of the union.
It will be simple if I just throw away the multibyte data members, but I want to keep them as much as possible because some functions in the library rely on these.
At first I thought I could use one-sized arrays instead, but I'm not sure if there is no side affects at all. Any recommendations?
It's not impossible to produce something that compiles with the -pedantic flag. But I don't think you can get the exact same semantics syntax-wise without C11.
The transformed packet_t
may look like this
typedef union packet_t {
struct { uint16_t id; uint16_t len; };
struct { uint16_t id8; uint16_t len8; uint8_t data[]; };
struct { uint16_t id16; uint16_t len16; uint16_t data16[]; };
struct { uint16_t id32; uint16_t len32; uint32_t data32[]; };
} packet_t;
The anonymous struct (C11) is required to nestle the fields as members of packet_t
. It's what makes p->id
valid still. The other id*
and len*
fields are dummies, because a flexible array member may not be the only member of a structure. They are there to make the access well-formed according to the common initial sequence guarantee of unions.
Looking at it, I can't help but feel you may be better off ditching the multiple data
fields altogether. A uint8_t
flexible array member can contain whatever the other two may contain.