先了解4个基本概念:
1、数据类型自身对齐值:即数据类型的大小(数组取数组成员类型的自身对齐值),如char的自身对齐值是1,short是2,int、float、double都是4,单位字节
2、结构体的自身对齐值:结构体成员中自身对齐值最大的那个值
3、指定对齐值:使用#pragma pack (value)时指定的对齐值alue
4、有效对齐值:自身对齐值和指定对齐值中较小的那个值
其次,数据存放必须满足以下两个法则:
法则1:有效对齐值为N的数据在内存中存放的起始地址必须是N的整数倍,即满足“存放起始地址 # N = 0”
法则2:结构体的变量占用的总长度必须是结构体有效对齐值的整数倍
有了以上基础,就能判断一个结构体占用内存的空间大小,下面举几个例子分析:
struct B
{
char b;
int a;
short c;
}
假设B从0x0000开始存放,并且默认编译环境默认的指定对齐值是4。第一个成员变量b的自身对齐值是1,比指定对齐值4小,所以有效对齐值是1,所以存放在0x0000空间。第二个成员a的自身对齐值是4,指定对齐值亦是4,所以有效对齐值是4,其存放起始气质必须是4的整数倍,所以必须存放在0x0004~0x0007空间。第三个成员c的自身对齐值是2,比指定对齐值4小,所以有效对齐值是2,紧接a占用空间的下一个起始地址0x0008满足2的整数倍,所以存放在0x0008~0x0009空间。最后,B的自身对齐值是具有最大自身对齐值的成员变量a的自身对齐值4,等于指定对齐值4,所以B总共占用0x0000~0x0011空间。
#pragma pack (2);
struct C
{
char b:
int a;
short c:
};
虽然结构体C的成员组成和结构体B的成员完全一致,但由于定义结构体前指定了对齐值为2,所以所有自身对齐值大于2的成员变量的有效对齐值都变成了2,而且结构体的最终有效对齐值也变成了2,所以占用空间比B小,如下图:
对于联合union,遵循的原则也是一样的,只不过union最终的长度是仅按照占用空间最大的那个成员来计算的,如
union D{
char a; //自身对齐值1
int b[5]; //自身对齐值4,占用空间最大为5×4 = 20
double c; //自身对齐值8
int d[3]; //自身对齐值4
};
按占用空间最大的成员长度计算,该union初步的长度的20字节,而所有成员中自身对齐值最大的是c,为8,所以该union长度要圆整到8的整数倍,即最终长度是24字节
在编程的时候,为减少中间的填补空间,基本原则是把结构体中的变量按照自身对齐值从小到大排列