Search code examples
c++gccvisual-studio-2013packing

Packed structures sizes and inheritance with different compilers


Consider a MWE:

#include <iostream>

struct A     {}         __attribute__((packed)) ;
struct B : A { int x; } __attribute__((packed)) ;

struct C : A { B y; }   __attribute__((packed)) ;

int main () {
    std::cout << "Size of A: " << sizeof(A) << std::endl;
    std::cout << "Size of B: " << sizeof(B) << std::endl;
    std::cout << "Size of C: " << sizeof(C) << std::endl;
};

On Linux I tried to compile it and run:

$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

$ g++ ./test.cpp && ./a.out 
Size of A: 1 
Size of B: 4 
Size of C: 5

As for A and B everything is clear. But what about C? What adds 1 byte to the C's size? Moreover, if you'll remove any inheritance relationships, either for B or C, C become of size 4. Using MS compilers (at least one that is shipped with VS 2013), I got 1, 4 and 4 sizes. Any explanation and details on that are appreciated.


Solution

  • [class.derived] / 7 (standard draft)

    ... A base class subobject may be of zero size (Clause [class]); however, two subobjects that have the same class type and that belong to the same most derived object must not be allocated at the same address ([expr.eq]).  — end note ]

    C has subobjects B::A (base of member y) and C::A (direct base) which are both of type A. y could otherwise be at the same address as the the empty base of C, but since it also has a base of same type, that base of B may not have the same address and therefore must be offset with padding. GCC follows this rule and only applies packing request to padding that was needed for correct alignment.