我们知道结构体是一种构造数据类型,里面可以有不同数据类型的成员。在这些成员中,不同的数据类型所占的内存空间是不同的。那么系统是怎么给结构体变量的成员分配内存的呢?或者说这些成员在内存中是如何存储的呢?
1.结构体对齐规则
结构体对齐规则首先要看有没有用#pragma pack(n) 宏声明,n必须是2的幂次方,如1,2,4,8...,当用#pragma pack(n)指定时,有效对齐值为:n和结构体成员中长度最长的类型相比较小的长度
在没有#pragma pack这个宏的声明下,有效对齐值为:结构体中最长的成员的长度
遵循下面三个原则:
1、第一个成员的首地址为0.
2、每个成员的首地址是自身大小的整数倍
3、结构体的总大小一定要为有效对齐值的整数倍
下面我们来看例子:
没有#pragma pack(n) 宏声明的情况下:
a的所在内存首地址为0,其次排b,根据第二条规则,0地址后面得1不是b大小2的整数倍,所以1地址为空,2地址是short大小的整数倍,所以地址2,3放b,最后4地址是int大小的整数倍所以c占4,5,6,7地址,我们再来看一下最后一条规则,本例有效对齐值是4,结构体占了8个字节,是4的整数倍,所以本结构体的大小为8字节。
然后我们再来把顺序换一下
这里需要考虑的就是char a占到第8个地址,但8+1=9不是4的整数倍,所以要把后面三个地址9,10,11都占掉(放空),所以最后整个结构体大小为12。
接下来我们看看有#pragma pack(n) 宏声明的情况:
根据规则我们可以分析出,a占0地址,1地址为空,b占2,3地址,c占4地址,5地址为空,所以整个结构体大小为6。
接下来我们把宏定义指定的对齐值n改为4,由于结构体最大类型short所占字节大小为2,所以指定对齐值依然为2,宏定义无效。
我们只要按照规则来,其实结构体对齐并不难理解。
2.需要内存对齐的原因:
- 平台原因:某些平台只能在特定的地址处访问特定类型的数据
- 性能原因:
- 数据结构应该尽可能在自然边界上对齐
- 访问未对齐的内存,处理器需要作两次内存访问。而对齐的内存仅需要访问一次