不同编译器的压缩结构大小和继承

Packed structures sizes and inheritance with different compilers

考虑 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;
};

在 Linux 我尝试编译它 运行:

$ 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

至于A和B,一切都清楚了。但是 C 呢?什么使 C 的大小增加 1 个字节?此外,如果您删除 B 或 C 的任何继承关系,则 C 的大小变为 4。使用 MS 编译器(至少是 VS 2013 附带的编译器),我得到了 1、4 和 4 大小。对此的任何解释和细节表示赞赏。

[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 具有子对象 B::A(成员 y 的基)和 C::A(直接基),它们都是 A 类型。 y 可能与 C 的空基地址相同,但由于它也有相同类型的基地址,因此 B 的基地址可能不相同,并且因此必须用填充来抵消。 GCC 遵循此规则,仅将打包请求应用于正确对齐所需的填充。