内存对齐
#pragma pack(8)
struct TestStruct4 {
char a;
long b;
};
struct TestStruct5
{
char c;
TestStruct4 d;
long long e;
};
#pragma pack()
问题: A),sizeof(TestStruct5) = ?
B), TestStruct5 的 c 后面空了几个字节接着是 d?
TestStruct4 中,成员 a 是 1 字节默认按 1 字节对齐,指定对齐参数为 8,这两个值中取 1,a 按 1 字节对齐;成员 b 是 4 个字节,默认是按 4 字节对齐,这时就按 4 字节对齐,所以 sizeof(TestStruct4)应该为 8;
TestStruct5 中,c 和 TestStruct4 中的 a 一样,按 1 字节对齐,而 d 是个结构,它是 8 个字节,它按什么对齐呢?对于结构来说,它的默认对齐方式就是它的所有成员使用的对齐参数中最大 的一个,TestStruct4 的就是 4。所以,成员 d 就是按 4 字节对齐。成员 e 是 8 个字节,它是默认按 8 字节对齐,和指定的一样,所以它对到 8 字节的边界上,这时,已经使用了 12 个字节了,所以又添加了 4 个字节的空,从第 16 个字节开始放置成员 e。这时,长度为 24,已经可以被 8(成员 e 按 8 字节对齐)整除。这样,一共使用了 24 个字节。内存布局如下(*表示空闲内存,1 表示使用内存。 单位为 1byete):
a b
TestStruct4 的内存布局:1***,1111,
c d(TestStruct4.a TestStruct4.b ) e
TestStruct5 的内存布局: 1***, 1***, 1111, ****, 11111111
这里有三点很重要:
首先,每个成员分别按自己的方式对齐,并能最小化长度。
其次,复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。
然后,对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。
补充一下,对于数组,比如:char a[3];它的对齐方式和分别写3个char是一样的。也就是说它还是按1个字节对齐。如果写: typedef char Array3[3];Array3 这种类型的对齐方式还是按 1 个字节对齐,而不是按它的长度。
但是不论类型是什么,对齐的边界一定是 1,2,4,8,16,32,64....中的一个。