2017-02-28 60 views
0

继承考虑一个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呢?什么增加了1个字节到C的大小?此外,如果您将删除任何继承关系,无论是B还是C,C都变成了大小4.使用MS编译器(至少有一个与VS 2013一起发布),我获得了1,4和4的大小。任何解释和细节在此表示赞赏。

+1

可能的重复[在使用gcc时,为什么Linux和Windows上的打包结构的大小不同?](http://stackoverflow.com/questions/7789668/why-would-the-size-of-a -packed-structure-be-different-on-linux-and-windows-when) – MSD

+0

@saranyadeviM,我已经看到了这个问题。在我看来,它讨论了为什么可以用不同的方式打包结构的原因(!)。我更感兴趣的是继承如何影响包装的结果,以及继承与组合混合如何将1字节添加到结构的大小。所以,我相信我的问题更具体。 :) – CaptainTrunky

回答

2

[class.derived]/7(草案标准)

...的基类的子对象可以是零大小(第[类])的;但是,具有相同类类型且属于相同最多派生对象的两个子对象不得分配在相同地址([expr.eq])中。 - 注完]

C具有子对象B::AC::A(直接基)(构件y的基础),其均为A类型。 y可能与C的空白基地址相同,但由于它也具有相同类型的基地址,因此B的基地址可能不具有相同地址,因此必须用填充补偿。 GCC遵循此规则,并仅将包装请求应用于正确对齐所需的填充。

+0

听起来很合理。这回答了我原来的问题,但又升起另一个问题:当这个假设不成立时,是否有可能破坏某些东西?唯一想到的就是使用指针作为关键。在这种情况下,他们必须有所不同。但这是相当奇特的事情。 – CaptainTrunky

+0

@CaptainTrunky好问题。我认为任何依赖于此的代码都必须相当复杂,但这可能只是缺乏我的想象力。事实上,处理对象身份的事情,比如使用指针作为关键字可能会受到影响。 – user2079303