Hello :
Is the following code an undefined behavior?
union {
int a;
int b;
} u;
u.a = 3;
printf("%d\n", u.b);
(I rush in where angels fear to tread...)
First, there's no problem with the issue mentioned in your
subject line: It's perfectly all right to have several union members
with distinct names but the same type. If that were not so, even
something as simple as `union { int i; time_t t; } u;' could be in
trouble. See also 6.2.5p20, which says that union members have
"possibly distinct" types.
The "write one member, read another" question has been discussed
more than once, and my impression of the debates is that there have
been two camps: Not "It's legal" and "It's illegal," but "It's legal"
and "You'll probably get away with it, but it might not be squeaky-
clean, and my head hurts can we talk about something else, please?"
(I'm in the latter camp.)
It's clear (from 6.2.6.1) that writing `u.a' deposits bytes that
represent `3', and that `u.b' thereby receives the same bytes. No
argument there: The storage allocated to `u.b' holds a representation
of `3'.
The part that makes my head ache is figuring out whether the
compiler is required to "notice" that storing to `u.a' affects the
value of `u.b'. If the compiler has already loaded `u.b' into a
register, say, is it required to re-fetch because `u.a' was changed?
Is the compiler allowed to consider `u.b' uninitialized because it
has never been stored to, despite the store to `u.a'?
To those in the "It's legal" camp, I offer a few puzzling and
possibly disturbing points:
- The footnote to 6.2.5p21 points out that "an object with union
type can only contain one member at a time" -- meaning that if
`u' contains `u.a', it does not contain `u.b'. Footnotes, of
course, are suggestive but non-normative.
- The footnote to 6.5.2.3p3 supports the "It's legal" camp by
describing the mechanism of type punning. Footnotes, of course,
are suggestive but non-normative.
- 6.5.2.3p5 gives a "special guarantee" for union members that
are structs, but does not extend a similar guarantee for other
member types.
- 6.7.2.1p14 has the normative language for the first footnote
mentioned above: "The value of at most one of the members can be
stored in a union object at any time." Your `u' can hold `u.a'
or `u.b', but not both at once.
Those are the citations I can find (if I've missed any I'm sure
others will point them out). Their cumulative impression on me is
that the matter is not settled beyond doubt, but the aforementioned
angels may see things differently.
As a practical matter, it's not all that important what I think
or what the angels think, but what the providers of your compilers
think. If a compiler does something unfortunate with your code you
will find yourself retracing this same argument with implementors
who are trying to stamp NOT A BUG on your complaint. If the angels
weigh in on your side, the implementors of the offending compiler
may eventually accede and agree to ship a fix -- "In a forthcoming
release," oh joy, oh joy. I think you might choose better battles:
Fight over things you Really Really Need and are Really Solid Bugs,
and don't waste troops trying to subjugate the unpopulated hinterland.