首先说说为什么要对齐。为了提高效率,计算机从内存中取数据是按照一个固定长度的。以32位机为例,它每次取32个位,也就是4个字节(每字节8个位)。字节对齐有什么好处?以int型数据为例,如果它在内存中存放的位置按4字节对齐,也就是说1个int的数据全部落在计算机一次取数的区间内,那么只需要取一次就可以了。如果不对齐,很不巧,这个int数据刚好跨越了取数的边界,这样就需要取两次才能把这个int的数据全部取到,这样效率也就降低了。
内存对齐的基本原则:
1.结构体内成员按自身按自身长度自对齐。
自身长度,如char=1,short=2,int=4,double=8,。所谓自对齐,指的是该成员的起始位置的内存地址必须是它自身长度的整数倍。如int只能以0,4,8这类的地址开始
2.结构体的总大小为结构体的有效对齐值的整数倍
结构体的有效对齐值的确定:
1)当未明确指定时,以结构体中最长的成员的长度为其有效值
2)当用#pragma pack(n)指定时,以n和结构体中最长的成员的长度中较小者为其值。
3)当用__attribute__ ((__packed__))指定长度时,强制按照此值为结构体的有效对齐值
4)不管# pragma pack和__attribute__如何指定,结构体内部成员的自对齐仍然按照其自身的对齐值。
例子1、
struct AA{
char a;
int b;
char c;
}aa
sizeof(aa)=12
原因:char占一个字节,可以在任何地址开始,int占4个字节,只能从0、4、8...开始,对于本题,只能从4开始,尽管1-3都空着,最后的char占一个字节,所以总长度是9,由第二条原则,总长度必须是4的整数倍,所以只能是12.
2、
struct AA{
char a;
char c;
int b;
}aa
sizeof(aa)=8
原因:char占一个字节,从地址1开始,紧跟着的char也占一个字节,从地址2开始,int占4字节,共6字节,有效对齐长度是sizeof(int)=4,所以是8.
3、
#pragma pack(2)
struct AA{
char a;
int b;
char c;
}aa
sizeof(aa)=10(注:在vs2010下运行结果是8,应该是不同编译器对于内存的分布进行优化,实际做题还是以10位结果)原因:同例1,总长度是9字节,因为结构体的有效对齐长度在pack指定的2和int的4中取较小的值2,所以总长度是10;如果#pragma pack(8),则有效对齐长度为4,总长度为12.
4、
struct AA{
char a;
int b;
char c;
}__attribute__((__8__))aa
sizeof(aa)=16
原因:同例1,总长度是9字节,因为结构体的有效对齐长度在强制指定的8字节,所以结果为16;若果指定为2,则结果为10.
5、在一个16位的机器上,一下结构由于数据边界对齐浪费了多少空间?
struct
{
char a;
int b;
char c;
}
解:在16位的机器上,int占2个字节,所以整个结构体总长度是4,但由于字节对齐,实际占用长度是6,也就是浪费两个字节。