为什么编译器(例如gcc)以这种方式处理派生类的内存布局?

时间:2014-05-24 05:58:54

标签: c++ gcc object-model

这是我的cpp代码。

#include <iostream>
using namespace std;

class A {
public:
    int val;
    char a;
};

class B: public A {
public:
    char b;
};

class C: public B {
public:
    char c;
};

int main()
{
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    cout << sizeof(C) << endl;

    return 0;
}

程序的输出(在gcc中)是:

8
12
12

这个输出让我很困惑。

我知道对齐可能是sizeof(A)等于8的原因。(sizeof(int) + sizeof(char) + 3 bytes padding

我还猜测sizeof(B)(sizeof(B) == sizeof(A) + sizeof(char) + 3 bytes padding)的扩展是为了避免重置发生时的重叠。 (是吗?)

但我真的不知道为什么sizeof(B)等于sizeof(C)。

非常感谢。

1 个答案:

答案 0 :(得分:13)

GCC和Clang都遵循Itanium C++ ABI文件,该文件指定:

...实现可以在任何类的尾部填充中自由分配对象,这些对象在C ++ 98中不是POD

class A是POD,因此编译器无法将内容放入其填充中。 class B不是POD,因此编译器可以自由地在基类布局中重用派生对象成员的填充。这里的基本思想是C ++类布局应该镜像POD类型的等效C结构布局,但是对其他类没有限制。由于“POD”的含义已多次更改,因此它们明确使用了C ++ 98中的定义。

编辑:关于理由。 POD类型是非常简单的类,可以在C中实现为struct。对于这些类型,布局应该与C编译器创建的布局相同。特别是他们希望允许memcpy之类的C工具用于A。如果char b;位于A的填充范围内,则memcpy会将其销毁。