为了加快数据存取的速度,编译器默认情况下会对结构体成员和结构体本身存储位置进行处理,使其存放的起始地址是一定字节数的倍数,而不是顺序存放,称为字节对齐.
(以下这3条规则摘自姜学锋,周果清,刘君瑞老师共编的《C++程序设计》,写得很好,在此表示感谢!) (个人认为,这本书在这一节方面写得要优于《深入理解计算机系统》)
设对齐字节数为n(n = 1,2,4,8,16),每个成员内存长度为Li,Max(Li)为最大的成员内存长度,字节对齐规则是:
1. 结构体对象的起始地址能够被Max(Li)所整除;
2. 结构体中每个成员相对于起始地址的偏移量,即对齐值应是min(n,Li)的倍数.若不满足对齐值的要求,编译器会在成员之间填充若干个字节;
3. 结构体的总长度值应是min(n,Max)(Li)的倍数,若不满足总长度值的要求,编译器在为最后一个成员分配空间后,会在其后填充若干个字节. (VC默认的对齐字节数n=8)
//第一个范例
int main()
{
struct s {
int i;
char ch;
short c;
};
printf("%d", sizeof( struct s ));
return 0;
}
//结果为:4+1+X+2=8 (X=1,满足于对齐规则第2条)
//第二个范例
int main()
{
struct s {
char ch;
int i;
short c;
};
printf("%d", sizeof( struct s ));
return 0;
}
//结果为:1+X+4+2+Y=12 (X=3,Y=2,分别满足于对齐规则第2条和第3条)
//使用pragma pack(push,n)和pragma pop组合
//第三个范例
#pragma pack(push,2) //此处n=2,(相当于将VC默认的对齐字节数设定为n=2)
int main()
{
struct s {
int i;
char ch;
short c;
};
#pragma pack(pop)
printf("%d", sizeof( struct s ));
return 0;
}
//结果为:4+1+X+2=8(X=1,满足于对齐规则第条)
//第四个范例
#pragma pack(push,4) //此处n=4,(相当于将VC默认的对齐字节数设定为n=4)
int main()
{
struct s {
int i;
char ch;
short c;
};
#pragma pack(pop)
printf("%d", sizeof( struct s ));
return 0;
}
//结果为:4+1+X+2=8(X=1,满足于对齐规则第条)
//第五个范例
#pragma pack(push,8) //此处n=8,(相当于将VC默认的对齐字节数设定为n=8)
int main()
{
struct s {
int i;
int y;
char ch;
short c;
};
#pragma pack(pop)
printf("%d", sizeof( struct s ));
return 0;
}
//结果为:4+4+1+X+2=12(X=1,满足于对齐规则第2条)