摘要:编译器如何在编译过程中静态确定 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 许可协议
对于 POD(普通旧数据),规则通常是:
完成上述操作后,结构的大小就是 S 的值。
此外:
考虑您的
TestClass3
: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。所以
TestClass3
的大小是32字节。对于基本类型(
int
,double
等),对齐要求是实现定义的,通常主要由硬件决定。在许多处理器上,当数据具有一定的对齐方式时(通常当其在内存中的地址是其大小的倍数时)加载和存储数据会更快。除此之外,上述规则主要来自逻辑。他们将每个成员放置在必须满足对齐要求的位置,而不会占用不必要的空间。脚注
1对于一般情况,我将其表述为使用对齐要求的最小公倍数。但是,由于对齐要求始终是 2 的幂,因此任何一组对齐要求的最小公倍数是其中最大的。