I'm testing a small code fragment and I'm surprised the same representation of 4 bytes as put into std::array and std::tuple yield different in-memory layouts
#include <iostream>
#include <tuple>
#include <array>
struct XYZW {
uint32_t x;
uint32_t y;
//std::array<uint8_t,4> z;
std::tuple<uint8_t, uint8_t, uint8_t, uint8_t> z;
uint32_t w;
};
int main() {
XYZW i;
i.z = {255, 0, 0, 0};
uint32_t z = (*reinterpret_cast<uint32_t*>(&i.z));
std::cout << z << " \n";
}
For tuple the output is: 4278190080
, while for the array it is: 255
.
Is this expected?
CodePudding user response:
std::array
has a layout specified by the standard, but std::tuple
does not, and can be anything the implementation wants.
So it's expected that they may differ, but of course they may also happen to choose the same layout, on some compilers/versions/platforms - there's just no guarantee.
In practice one of the easiest ways to implement std::tuple
is recursively, as it was originally done in the Loki library. This will lay the fields out in reverse order (the most-base class, whose subobject comes first, is the leaf for the last member of the typelist). That's not the only possible implementation though, and I have observed the field order differing between compilers/standard library implementations.
NB. as mentioned in a comment, your current diagnostic has UB - however, you can hexdump the 4 bytes at reinterpret_cast<char*>(&i.z)
safely and get an equivalent result.
CodePudding user response:
std::array and std::tuple yield different in-memory layouts
Is this expected?
Yes, this possibility is to be expected, although that isn't guaranteed.
To be more specific, the memory order of array elements are such that lower indices are in lower memory addresses. The memory order of tuple elements is unspecified. As a side-effect of the way that tuples are typically implemented, the inverse memory order is typical.
uint32_t z = (*reinterpret_cast<uint32_t*>(&i.z));
This results in undefined behaviour. Tuples aren't (guaranteed to be) standard layout types, so you may not alias them as their first member.