C类的大小是如何确定的?

新手上路,请多包涵

摘要:编译器如何在编译过程中静态确定 C++ 类的大小?

详情

我试图了解用于确定类将使用多少内存以及如何对齐内存的规则。

例如下面的代码声明了 4 个类。前 2 个各 16 个字节。但是 3 是 48 个字节,尽管它包含与第一个 2 相同的数据成员。而第四个类具有与第三个相同的数据成员,只是顺序不同,但它是 32 个字节。

 #include <xmmintrin.h>
#include <stdio.h>

class TestClass1 {
  __m128i vect;
};

class TestClass2 {
  char buf[8];
  char buf2[8];
};

class TestClass3 {
  char buf[8];
  __m128i vect;
  char buf2[8];
};

class TestClass4 {
  char buf[8];
  char buf2[8];
  __m128i vect;
};

TestClass1 *ptr1;
TestClass2 *ptr2;
TestClass3 *ptr3;
TestClass4 *ptr4;
int main() {
  ptr1 = new TestClass1();
  ptr2 = new TestClass2();
  ptr3 = new TestClass3();
  ptr4 = new TestClass4();
  printf("sizeof TestClass1 is: %lu\t TestClass2 is: %lu\t TestClass3 is: %lu\t TestClass4 is: %lu\n", sizeof(*ptr1), sizeof(*ptr2), sizeof(*ptr3), sizeof(*ptr4));
  return 0;
}

我知道答案与类的数据成员的对齐有关。但我试图准确理解这些规则是什么以及它们在编译步骤中是如何应用的,因为我有一个具有 __m128i 数据成员的类,但该数据成员不是 16 字节对齐的,这当编译器使用 movaps 生成代码来访问数据时,会导致段错误。

原文由 Gabriel Southern 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 735
1 个回答

对于 POD(普通旧数据),规则通常是:

  • 结构中的每个成员都有一些大小 s 和一些对齐要求 a
  • 编译器从大小 S 设置为零和对齐要求 A 设置为一(字节)开始。
  • 编译器按顺序处理结构中的每个成员:
  1. 考虑成员 对齐要求 a 。如果 S 当前不是 a 的倍数,则向 S 添加足够的字节,使其成为 a 的倍数。这决定了会员的去向;它将从结构的开头开始偏移 S (对于 S 的当前值)。
  2. A 设置为 Aa 的 最小公倍数1 。
  3. s 添加到 S ,为成员留出空间。
  • 当为每个成员完成上述过程时,考虑结构 对齐要求 A 。如果 S 当前不是 A 的倍数,则将其添加到 S 使其成为 A 的倍数。

完成上述操作后,结构的大小就是 S 的值。

此外:

  • 如果任何成员是一个数组,它的大小就是元素个数乘以每个元素的大小,它的对齐要求就是一个元素的对齐要求。
  • 如果任何成员是结构,则其大小和对齐要求如上计算。
  • 如果任何成员是联合体,则其大小是其最大成员的大小加上刚好足以使其成为所有成员对齐的最小公倍数1的倍数。

考虑您的 TestClass3

  • S 从0开始, A 从1开始。
  • char buf[8] 需要8个字节和对齐1,所以 S 增加8到8, A 保持1。
  • __m128i vect 需要 16 个字节和对齐 16。首先,必须将 S 增加到 16 以提供正确的对齐。然后 A 必须增加到 16。然后 S 必须增加 16 为 vect 腾出空间,所以 S 现在是 32。
  • char buf2[8] 需要8个字节和对齐1,所以 S 增加8到24, A 保持16。
  • 最后, S 是 24,不是 A (16)的倍数,所以 S 必须增加 8 到 32。

所以 TestClass3 的大小是32字节。

对于基本类型( intdouble 等),对齐要求是实现定义的,通常主要由硬件决定。在许多处理器上,当数据具有一定的对齐方式时(通常当其在内存中的地址是其大小的倍数时)加载和存储数据会更快。除此之外,上述规则主要来自逻辑。他们将每个成员放置在必须满足对齐要求的位置,而不会占用不必要的空间。

脚注

1对于一般情况,我将其表述为使用对齐要求的最小公倍数。但是,由于对齐要求始终是 2 的幂,因此任何一组对齐要求的最小公倍数是其中最大的。

原文由 Eric Postpischil 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题