I am unsure of whether or not the code has pointer aliasing (or other standard conformance issues) in the asserts cast. It seems that a pointer to the union type should be a
Under C89, a pointer of structure type which identifies a member of a union may be used to inspect any member which is part of a Common Initial Sequence shared with the type of data stored therein. This in turn generally implies that a pointer to any structure type could be used to inspect any member of the Common Initial Sequence shared with any other type (such behavior would have been unambiguously defined if the object happened to be a member of a declared union object, and the only practical way for a compiler to yield the required behavior in those cases would be to uphold it for all).
C99 added an additional requirement that the CIS guarantees only apply when a complete union type containing both structures is visible, which some compiler writers seem to think means it only applies to accesses performed directly through union types. The authors of such compilers seem to think a function that would need to handle functions with a common header like:
struct smallThing { void *next; uint16_t length; uint8_t dat[2]; };
struct bigThing { void *next; uint16_t length; uint8_t dat[65528]; };
should be to extract out the header like:
struct uHeader { void *next; uint16_t length; };
struct smallThing { uHeader head; uint8_t dat[2]; };
struct bigThing { uHeader head; uint8_t dat[15994]; };
or use union-type objects for everything, even though using uHeader would
increase the size of struct smallThing
by 50% (and totally break any code that
had been reliant upon its layout), and using unions for everything when most objects only need to be small would increase memory usage a thousandfold.
If one needs code to be compatible with compilers that essentially ignore the Common Initial Sequence rule, one should regard the Common Initial Sequence rule as essentially useless. Personally, I think it would be better to document that only compilers that honor the CIS should be considered suitable for use with one's code, rather than bending over backward to accommodate unsuitable compilers, but I think it's important to be aware that compilers like the latter ones exist.
So far as I can tell, clang and gcc do not honor the CIS rule in any useful way except when the -fno-strict-aliasing
flag is set. I don't know about other compilers.
union
don't pad, they just overlay their members. The first member of any struct
is guaranteed to start right off, without padding. In general struct
that start with the same members of same type are guaranteed to have the same layout for that initial part.
That should be fine. C11, 6.5.2.3/6 ("Structure and union members") says:
One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.
(C++ makes the same guarantee (C++11, 9.2/18) for standard-layout unions.)