The C standard mandates that all pointers to union
s have the same representation and alignment requirements.
It mandates the same for all pointers to struct
s.
Thus my question:
Why does the standard not mandate that pointers to union
s have the same representation and alignment requirements as pointers to struct
s? (I would very much appreciate an example of an implementation taking advantage of this.)
Or did I simply miss the relevant text?
The relevant quote from the draft standard n1570 (C11 final draft):
6.2.5 Types § 28
A pointer to void
shall have the same representation and alignment requirements as a
pointer to a character type.48) Similarly, pointers to qualified or unqualified versions of
compatible types shall have the same representation and alignment requirements. All
pointers to structure types shall have the same representation and alignment requirements
as each other. All pointers to union types shall have the same representation and
alignment requirements as each other. Pointers to other types need not have the same
representation or alignment requirements.
Neither the 1989 ANSI C Rationale nor the ISO C99 Rationale discusses this.
I doubt that there's any strong reason for the lack of such a requirement. Probably the committee didn't want to impose unnecessarily strict requirements. I also doubt that there are any real-world implementations where pointers to structs and pointers to unions don't have the same representations.
Consider, for example, that a struct can contain a single union member, and vice versa, so there's probably no good reason for an implementation to use different representations -- nor is there any good reason for the standard to require all implementations to use identical representations.
The reason all struct pointers "smell alike" is to permit the use of pointers to incomplete types. For example:
struct foo;
void func(struct foo *param);
struct foo { /* member declarations */ };
The compiler doesn't have to know anything about struct foo
other than that it's a struct
type to know how to generate a call to func()
.
The same applies to incomplete union types. But an incomplete struct type cannot be completed as a union, or vice versa, so there's no great benefit in being able to assume that they have the same representation.
Even though the Standard would not require that an implementation do so, an implementer may recognize the usefulness of having a type of pointer which might alias any of several types with different alignment requirements (e.g uint8_t
, uint16_t
, uint32_t
, and uint64_t
), but need only comply with the alignment of the type actually used for access (e.g. need only be 16-bit aligned when used to access a uint16_t
). Using pointers of a union type to access things that aren't actually objects of union type may seem strange, but C offers no other syntax to suggest that a pointer may be used to alias things of certain specific types in addition to the actual type used for access.
If the system used word addresses, it might be reasonable to say that all structures will be padded to a whole number of words and must be aligned on word boundaries, but imposing such a requirement on unions would make it impossible to use them for the above-described purpose. On such a system, it might consequently make sense allow pointers to unions to identify locations at individual-byte boundaries (when directly accessing only things for which the alignment would be satisfactory) even though pointers to structures would be limited to word boundaries, and even though this might cause union pointers to be larger than struct pointers.