Guaranteed memory layout for standard layout struct with a single array member of primitive type
One thing that is not guaranteed about the layout is endianness i.e. the order of bytes within a multi-byte object. write_bytes(&x, sizeof(A))
is not portable serialisation across systems with different endianness.
A
can bereinterpret_cast
to a pointer to its first data member (which is, presumably,data[0]
?)
Correction: The first data member is data
, which you can reinterpret cast with. And crucially, an array is not pointer-interconvertible with its first element, so you cannot reinterpret cast between them. The address however is guaranteed to be the same, so reinterpreting as data[0]
should be fine after std::launder
as far as I understand.
There is no padding in between elements of an array of primitive type
Arrays are guaranteed to be contiguous. sizeof
of an object is specified in terms of padding required to place elements into an array. sizeof(T[10])
has exactly the size sizeof(T * 10)
. If there is padding between non-padding bits of adjacent elements, then that padding is at the end of the element itself.
Primitive type is not guaranteed to not have padding in general. For example, the x86 extended precision long double
is 80 bits, padded to 128 bits.
char
, signed char
and unsigned char
are guaranteed to not have padding bits. C standard (to which C++ delegates the specification in this case) guarantees that the fixed width intN_t
and uintN_t
aliases do not have padding bits. On systems where that is not possible, these fixed width types are not provided.
If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member. Otherwise, its address is the same as the address of its first base class subobject (if any). [Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note]
Hence, the standard guarantees that
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.
Hence, the following are true
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));