【问题标题】:Why is the size of my class larger than the sum of its members? [duplicate]为什么我的班级人数大于其成员的总和? [复制]
【发布时间】:2016-05-15 19:31:39
【问题描述】:

有人可以帮我理解sizeof() 操作员的行为吗?

 #include <iostream>

using namespace std;

class A{
    int first;
    double last;
    public:
    A(int a)
    {
        cout << a << endl;
    }
};
int main()
{
    A a(3);
    cout << sizeof(a) << endl;
    return 0;
}

此代码将我的大小打印为 16 个字节。类的大小是根据其成员计算的。所以我有 4 个字节 (int) + 8 个字节 (double) = 12。

那么为什么我得到了 16 个字节?

当我注释掉 intdouble 成员时,我得到 1 个字节。

【问题讨论】:

  • 如果您使用 Visual C++,请参阅 msdn.microsoft.com/en-us/library/xh3e3fd0.aspx 并尝试使用 /Zp1 选项将输出设为 12。
  • 不,我用的是普通的g++编译器
  • GCC 和 Visual C++ 一样“普通” :) 无论如何,每个 C++ 编译器都提供类似的选项。这些东西本质上是特定于实现的。
  • 打包和字节对齐和填充可能会导致您看到的内容。您还应该知道,可以通过精确控制大小且没有填充来构建您的结构或类。但这是一个不同的问题。

标签: c++ class sizeof


【解决方案1】:

只要 POD 类与 C 结构兼容,类中字段的布局是实现定义的。然而,即使在 C 结构实现中,也出于各种原因(例如性能)添加填充。因此,您的编译器可能会在 int 字段之后添加四个字节的填充,以使 double 字段从 8 字节对齐的地址开始。

如果您特别需要不发生这种情况,有一些方法可以控制类/结构的对齐和填充,这些方法因编译器而异。例如,GCC 具有类似于__attribute__((packed)) 的语法,它将删除该填充。这很少需要 - 主要是在结构需要映射到设备寄存器时 - 并且通常会损害性能,因此请尽可能避免使用它。

【讨论】:

    【解决方案2】:

    编译器为速度和其他因素布置类内部,不一定是为了空间节省,所以它可能会在一个大小后面留下一个空的4字节块- 4 个元素,然后再拟合下一个元素。这使得在现代架构(基于 64 位 = 8 字节)上更快地访问下一个元素。

    另外,请注意,类对象的 sizeof 可能包含您不知道的其他数据,例如指向虚函数表的指针等。这是编译器的工作,并且有权将最终代码放入其中运行正确且快速。

    【讨论】:

    • 这基本上是对的,只是编译器对类的布局方式不一定针对速度进行了优化。其他因素也被考虑在内。特别是,如果一个平台有一个被其他编译器使用的次优 ABI,那么新的编译器最终可能会使用该 ABI 来实现兼容性,即使他们可以通过放弃兼容性来提供更快的 ABI。
    • 我认为虚函数表是作为整个类的属性保存的,而不是与类的每个实例一起保存的。
    【解决方案3】:

    编译器将成员打包到类中的默认方式是尝试与字边界对齐,即字大小的倍数(64 位机器上为 8 个字节)。要停止打包使用#pragma pack(1) 或编译器选项/Zp。这会强制编译器将成员相互挤压。

    一个类的大小不允许为零,因为这可能意味着指向两个不同对象的指针相同,因此它的最小大小为 1 个字节。

    【讨论】:

    • 是的,谢谢。这是有道理的。
    猜你喜欢
    • 1970-01-01
    • 2016-10-26
    • 2015-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多