For example,
#include <cstdint>
#include <cstdio>
struct ipv4addr {
union {
std::uint32_t value;
std::uint8_t parts[4];
};
};
int main() {
ipv4addr addr;
addr.value = static_cast<std::uint32_t>(-1);
std::printf("%hhu.%hhu.%hhu.%hhu",
addr.parts[0], addr.parts[1], addr.parts[2], addr.parts[3]);
}
Per cppref,
The details of that allocation are implementation-defined, and it's undefined behavior to read from the member of the union that wasn't most recently written.
So looks like the code invokes undefined behavior. But the page also says
If two union members are standard-layout types, it's well-defined to examine their common subsequence on any compiler.
I don't quite understand this. Does it make the code behavior well-defined?
Also note cppref's description on type aliasing.
Whenever an attempt is made to read or modify the stored value of an object of type
DynamicType
through a glvalue of typeAliasedType
, the behavior is undefined unless one of the following is true:
- [...]
AliasedType
isstd::byte
,char
, orunsigned char
: this permits examination of the object representation of any object as an array of bytes.
I guess this applies to std::uint8_t
as well. No?