The type-access rules in section 6.5 paragraph C of C11 draft N1570 make no provision for an object of struct
or union
type to have its storage accessed by anything other than an lvalue of that union
type, an lvalue of another type that contains such a union
, or an lvalue of character type.
A quality compiler that can see that a pointer or lvalue of one type is being used to derive a pointer or lvalue of another which is then accessed should be able to recognize that an access to the latter, made in a context where the derivation is visible, is an access to the former. I think the authors of the Standard thought that sufficiently obvious that it could go without saying, especially since even something like someUnion.intMember = 3;
would invoke UB otherwise. The left-hand operand of the assignment is an lvalue of type int
, and there is no provision that would allow an lvalue of type int
to be used to access an object of union type. The range of situations where a compiler would recognize that an access via derived pointer or lvalue is an access to the parent is a Quality of Implementation issue; the Standard offers no guidance as to what should be expected from a "good" implementation.
As for what clang and gcc allow, they seem to recognize that an access to someUnion.someArray[i]
is an access to the union, but they do not recognize *(someUnion.someArray+i)
likewise, even though the Standard defines the two constructs as equivalent. Since the Standard doesn't require that implementations recognize either (nor even the obvious someUnion.intMember
), the disparity does not make clang and gcc non-conforming. Nonetheless, it should be noted that they are astonishingly blind when it comes to recognizing lvalues based on unions.