不同编译器的压缩结构大小和继承
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 遵循此规则,仅将打包请求应用于正确对齐所需的填充。
考虑 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 遵循此规则,仅将打包请求应用于正确对齐所需的填充。