内存对齐的四大规则:
- 第一个成员在与结构体变量偏移量为0的位置处。
- 其他成员变量要对齐到某个数字(对其数)的整数倍的地址处。对其数=编译器默认的一个对齐数与该成员大小的较小者。
vs中默认的值是8
Linux中默认的值是4
- 结构体总大小为最大对其数(每一个成员变量都有一个对其数)的整数倍。
- 如果嵌套了结构体对齐到自己的最大对其数是整数倍处,结构体的整体大小就是最大对齐数(含嵌套结构体的对齐数)的整数倍。
注:在第二条中,是该成员,是当前的那个成员,不是其他的。
另一种说法(与四大规则的含义是一样的):
-
对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(
#pragma pack()
指定的数,这个数据成员的自身长度) 的倍数。 -
在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照
#pragma pack
指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
注: #pragma pack
的用法为#pragma pack(n)
,n可以取值为1 2 3等,表示设置为n字节对齐
举列说明:
struct st1
{
char a ;
int b ;
short c ;
};
St1 :char
占一个字节,起始偏移为0 ,int
占4个字节,#pragma pack()
指定的数与这个数据成员的自身长度之前的较小值4(VC6默认8字节对齐),所以int
按4字节对齐,起始偏移必须为4的倍数,所以起始偏移为4,在char后编译器会添加3个字节的额外字节,不存放任意数据。short
占2个字节,按2字节对齐,起始偏移为8,8正好是2的倍数,无须添加额外字节。到此第一次对齐结束,此时的内存状态为:
oxxx|oooo|oo
此时共占10个字节。还要继续进行结构本身的对齐,即第二次对齐,对齐将按照#pragma pack
指定的数值和结构(或联合)最大数据成员长度中,较小的那个数进行对齐,st1结构中最大数据成员长度为int
,占4字节,而默认的#pragma pack
指定的值为8,所以结果取两之较小数即按照4字节对齐,结构总大小必须为4的倍数,需添加2个额外字节使结构的总大小为12 。此时的内存状态为:
oxxx|oooo|ooxx
到此内存对齐结束。St1占用了12个字节而非7个字节。