Let's consider a union of integers of different sizes. Is it guaranteed that if a number fits the range of each of the integer types, it can be written to and read out from any of the union data members correctly?
E.g. this code
union U {
int32_t i;
int16_t s;
} u;
u.s = 1000;
std::cout<<u.i<<std::endl;
I verified that it prints correctly "1000" on one computer. Is it guaranteed to work the same on any other system? I guess on any system the endianness would be the same for any integer type, so it's rather a question whether the union is guaranteed to use the less significant bytes of the larger integer for the smaller one?
I know this has no chance to work for negative numbers, so let's consider non-negative numbers only.
No, that only works in little endian. In big endian the bytes are stored from the most significant position down. 0xdeadbeef
will be stored in memory as ef be ad de
in little endian and de ad be ef
big endian in memory so reading 2 bytes from the start address will result in 0xbeef and 0xdead in those machines respectively
However you're getting undefined behavior, because you're writing the smaller 2-byte field first then read the larger one. That means the high 2 bytes of int32_t
will contain garbage. That's disregarding the fact that using union
in C++ is already UB. You can only do that in C
If you write the larger field first the read the smaller one then it works even for signed types:
u.i = -1000;
std::cout << u.s << '\n';
This will print out as expected on a little endian machine