Yes, this is allowed and well-defined. According to §3.10 [basic.lval]:
10/ If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:
— the dynamic type of the object
[...]
Since here we store an int
and read through an int
, we access the object through a glvalue of the same dynamic type than the object, thus things are fine.
There even is a special caveat in the Standard for structures that share the same prefix. Or, in standardese, standard-layout types that share a common initial sequence.
§9.2/18 If a standard-layout union contains two or more standard-layout structs that share a common initial sequence, and if the standard-layout union object currently contains one of these standard-layout structs, it is permitted to inspect the common initial part of any of them. Two standard-layout structs share a common initial sequence if corresponding members have layout-compatible types and either neither member is a bit-field or both are bit-fields with the same width for a sequence of one or more initial members.
That is:
struct A { unsigned size; char type; };
struct B { unsigned length; unsigned capacity; };
union { A a; B b; } x;
assert(x.a.size == x.b.length);
EDIT: Given that int
is not a struct
(nor a class
) I am afraid it's actually not formally defined (I certainly could not see anything in the Standard), but should be safe in practice... I've brought the matters to the isocpp forums; you might have found a hole.
EDIT: Following the above mentionned discussion, I have been shown §3.10/10.