C++ - 对象填充的复杂性

C++ - object padding intricacies

本文关键字:复杂性 填充 对象 C++      更新时间:2023-10-16

我试图深入了解结构和类填充,所以我设计了一个我认为比我在有关该主题的教程中找到的许多示例更具挑战性的示例。我在使用 g++ 的 x64 机器中编译了它,但没有启用任何代码优化。我的代码如下:

class Example
{
private:
long double foobar;     // 10 bytes + 6 padded bytes as double follows
double barfoo;          // 8 bytes + 8 padded bytes
static float barbar;    // didn't count as it's a static member
float *fooputs;         // 8 bytes + 8 padded bytes
int footsa;             // 4 bytes, stored in the padded portion of float
char foo;               // 1 byte, stored in the padded portion of float
public:
int function1(int foo) { return 1; }
void function2(int bar) { foobar = bar; }
};
int main()
{
std::cout << sizeof(Example) << std::endl;   // 48 bytes
return 0;
}

虽然我看到Example的大小是 48 字节,但我预计它是 37 字节。关于我期望的论证如下:

  • foobar需要 10 个字节。如下double,填充还需要 6 个字节。
  • barfoo需要 8 个字节,因为它是double。无需填充,如mod(16,8) == 0
  • *fooputs需要 8 个字节,因为它是 x64 体系结构中的指针。无需填充,如mod(24,8) == 0
  • footsa需要 4 个字节作为整数,无需填充,如mod(32,4) == 0
  • foo需要 1 个字节作为字符。 无需填充。

由于结果与预期不同,我试图通过注释 in 和 out 类成员来了解C++如何评估Example到 48 字节的大小。因此,除了foobar的论证之外,我还假设了我为每个成员在内联评论中写的理由。

谁能解释一下我如何将大小评估为 48 字节以及我的理由是否正确?

你忘记了最后的填充sizeof返回数组中两个相邻成员之间的字节数。在您的情况下,alignof(long double)很可能是 16,因此每个Example实例都需要使用 16 字节对齐的地址。

因此,如果在 16 字节对齐的地址 A 处有Example的第一个实例,然后成员需要 37 个字节,则下一个Example实例不能存储在 A + 37 字节处,但需要存储在A+k* 16 处。满足 k * 16>= 37 的最小可能k是 3。这最终为您提供了数组中两个Example实例之间的字节数 3 * 16 = 48,这正好是sizeof(Example).