Given the code:
struct s1 {unsigned short x;};
struct s2 {unsigned short x;};
union s1s2 { struct s1 v1; struct s2 v2; };
static int read_s1x(struct s1 *p) { re
I believe that your code is conformant, and there is a flaw with the -fstrict-aliasing
mode of GCC and Clang.
I cannot find the right part of the C standard, but the same problem happens when compiling your code in C++ mode for me, and I did find the relevant passages of the C++ Standard.
In the C++ standard, [class.union]/5 defines what happens when operator =
is used on a union access expression. The C++ Standard states that when a union is involved in the member access expression of the built-in operator =
, the active member of the union is changed to the member involved in the expression (if the type has a trivial constructor, but because this is C code, it does have a trivial constructor).
Note that write_s2x
cannot change the active member of the union, because a union is not involved in the assignment expression. Your code does not assume that this happens, so it's OK.
Even if I use placement new
to explicitly change which union member is active, which ought to be a hint to the compiler that the active member changed, GCC still generates code that outputs 4321
.
This looks like a bug with GCC and Clang assuming that the switching of active union member cannot happen here, because they fail to recognize the possibility of p1
, p2
and p3
all pointing to the same object.
GCC and Clang (and pretty much every other compiler) support an extension to C/C++ where you can read an inactive member of a union (getting whatever potentially garbage value as a result), but only if you do this access in a member access expression involving the union. If v1
were not the active member, read_s1x
would not be defined behavior under this implementation-specific rule, because the union is not within the member access expression. But because v1
is the active member, that shouldn't matter.
This is a complicated case, and I hope that my analysis is correct, as someone who isn't a compiler maintainer or a member of one of the committees.