结构填充
假设这个 struct
是用 32 位编译器定义和编译的:
struct test_32 {
int a; // 4 byte
short b; // 2 byte
int c; // 4 byte
} str_32;
我们可能期望这个 struct
只占用 10 个字节的内存,但是通过打印 sizeof(str_32)
,我们看到它使用了 12 个字节。
发生这种情况是因为编译器将变量对齐以便快速访问。一种常见的模式是,当基类型占用 N 个字节时(其中 N 是 2 的幂,如 1,2,4,8,16 - 并且很少更大),变量应该在 N 字节边界上对齐( N 个字节的倍数)。
对于 sizeof(int) == 4
和 sizeof(short) == 2
所示的结构,常见的布局是:
int a;
存储在偏移量 0; 4 号。short b;
存储在偏移量 4; 2 号。- 偏移量为 6 的未命名填充; 2 号。
int c;
存储在偏移量 8; 4 号。
因此 struct test_32
占用 12 个字节的内存。在此示例中,没有尾随填充。
编译器将确保从 4 字节边界开始存储任何 struct test_32
变量,以便结构中的成员正确对齐以便快速访问。需要内存分配函数,如 malloc()
,calloc()
和 realloc()
,以确保返回的指针与任何数据类型的使用足够对齐,因此动态分配的结构也将正确对齐。
最终可能出现奇怪的情况,例如 64 位 Intel x86_64 处理器(例如 Intel Core i7 - 运行 macOS Sierra 或 Mac OS X 的 Mac),在 32 位模式下进行编译时,编译器将 double
对齐 4 字节边界; 但是,在相同的硬件上,当在 64 位模式下编译时,编译器将 double
对齐在 8 字节边界上。