Yes, the standard guarantees that it is safe to assert that. The relevant term here is layout compatible.
The standard defines that term in two parts. First it defines what a common initial sequence of data members is (but only for standard-layout structs): It is the sequence of data members that are equivalent between the two structs. The standard includes an example, but I'll use a slightly different one to avoid some technicalities:
struct A { int a; char b; };
struct B { int b1; char b2; };
struct C { int x; int y; };
In that example, the common initial layout of A
and B
is both of their members, while for A
and C
it is only their first respective members. It then defines structs as layout compatible if the common initial layout is simply the whole class.
If you have instances of two different layout-compatible types, like A
and B
in the above example, you *can* assume they have the same size:
static_assert(sizeof(A) == sizeof(B));
However, you *cannot* (in theory) cast between them without invoking undefined behaviour, because that violates aliasing rules:
A a{1, 'a'};
B* b = reinterpret_cast<B*>(&a); // undefined behaviour!
do_something_with(b);
What you can do, subject to the usual const
/volatile
rules as well as rules about data members being trivial (see When is a type in c++11 allowed to be memcpyed?), is use memcpy
to get data between layout-compatible structs. Of course, that wouldn't be possible of padding between members could be randomly different, as the current top answer suggests.
A a{1, 'a'};
B b;
memcpy(&b, &a, sizeof(b)); // copy from a to b
do_something_with(b);
If do_something_with
takes its argument by reference and modifies it then you would then need to copy back from b
to a
to reflect the effect there. In practice this would usually be optimised to be what you would expect the above cast to do.
The answer by atomsymbol gives an example that appears to contradict everything above. But you asked about what was in the standard, and a #pragma
that affects padding is outside of what is covered by the standard.
A
andB
or free to pad them differently – Kaolinassert
so you get a compile time error rather than a run time error, when things go bad (andassert
is also, usually, compiled out in release builds.static_assert
cannot be ignored). – Virilismstruct A {int x; int y;}; ...some code... struct B {int a;int b;};
-- Not guaranteed to be the same size. It all depends on the implementation details of "some code". Probably that's why the standard may not mention this -- too many edge cases would make the sizes different. – Zebapdastatic_assert
s in your code, even if you are not sure about how the standard handles your specific situation. Code withstatic_assert
s to validate assumptions is always safer than code that makes assumptions without validation. If at some point you find some platforms/situations where these asserts do fail, then congratulations: you just caught a bug at compile time that you otherwise probably would have missed. – Bismuthicstatic_assert
s are just for demonstration, I am not worried about thestatic_assert
themself, but about any code that might make the same assumption silently. Usingstatic_assert
to validate assumptions is a good suggestion and sometimes I even use it to document – Kaolinstruct bank_account { int money; int max_deposit; };
andstruct rectangle { int height; int width; };
, I wouldnt want to use arectangle
in place of abank_account
– Kaolinlanguage-lawyer
are about the formal rules of c++ as you can find them in the standard. Of course they do apply also to real code, but it doesnt need real code to discuss them – Kaolin