You cannot do this: &reinterpret_cast<PunnerToUInt32*>(&x)
The rules on reinterpret_cast
state:
When a pointer or reference to object whose dynamic type is DynamicType
is reinterpret_cast
(or C-style cast) to a pointer or reference to object of a different type AliasedType
, the cast always succeeds, but the resulting pointer or reference may only be used to access the object if one of the following is true:
AliasedType
is (possibly cv-qualified) DynamicType
AliasedType
and DynamicType
are both (possibly multi-level, possibly cv-qualified at each level) pointers to the same type T
AliasedType
is the (possibly cv-qualified) signed or unsigned variant of DynamicType
AliasedType
is an aggregate type or a union type which holds one of the aforementioned types as an element or non-static member (including, recursively, elements of subaggregates and non-static data members of the contained unions): this makes it safe to obtain a usable pointer to a struct or union given a pointer to its non-static member or element.
AliasedType
is a (possibly cv-qualified) base class of DynamicType
AliasedType
is char
or unsigned char
: this permits examination of the object representation of any object as an array of unsigned char
Because none of these are true for the combination of DynamicType
being float
and AliasedType
being PunnerToUInt32
the pointer may not be used to access the object, which you are doing. Making the behavior undefined.
For more information see: Why Doesn't reinterpret_cast Force copy_n for Casts between Same-Sized Types?
EDIT:
Breaking down the 4th bullet int bite size chunks yields:
- "
AliasedType
"
Here taken to be PunnerToUInt32
"is an aggregate type or a union type"
PunnerToUInt32
qualifies since it meets the qualifications of an aggregate type:
- array type
- class type (typically,
struct
or union
), that has
- no private or protected non-static data members
- no user-provided constructors, including those inherited from public bases (explicitly defaulted or deleted constructors are allowed)
- no virtual, private, or protected base classes
- no virtual member functions
"which holds one of the aforementioned types as an element or non-static member (including, recursively, elements of subaggregates and non-static data members of the contained unions)"
Again PunnerToUInt32
qualifies because of it's float fl
member
- "this makes it safe to obtain a usable pointer to a struct or union"
This is the final correct part as AliassedType
is a PunnerToUInt32
- "given a pointer to its non-static member or element"
This is a violation, because the DynamicType
which is x
is not a member of PunnerToUInt32
Because of the violation of part 5 operating on this pointer is undefined behavior.
If you care for some recommended reading you can check out Empty Base Optimization if not I'll give you the primary relevance here:
Empty base optimization is required for StandardLayoutTypes in order to maintain the requirement that the pointer to a standard-layout object, converted using reinterpret_cast
, points to its initial member
Thus you could exploit reinterpret_cast
's 4th bullet by doing this:
PunnerToUInt32 x = {13, 42.0F};
auto y = reinterpret_cast<PunnerToUInt32*>(&x.ui32);
Live Example