结构体的大小并不是结构体所有成员变量的大小的总和,而是一般大于这个总和的值,造成这种现象的原因是结构体的内存对齐。
对齐规则:
- 第一个成员的偏移量在结构体地址偏移量为0处
- 其他成员变量的偏移量为某个数字(对齐数)的整数倍
- 对齐数为系统默认的对齐数与成员变量所占字节数的最小值
- 结构体的总大小为所有成员变量的最大对齐数的整数倍
- 如果有嵌套的结构体,那嵌套的结构体偏移量为嵌套结构体最大对齐数的整数倍,整体的结构体大小为所有对齐数(含嵌套结构体)的最大值
例如:
struct S1
{
char a;//自身大小1/默认对齐数4/对齐数1 ---偏移量为0
char b;//自身大小1/默认对齐数4/对齐数1 ---偏移量为1
int c;//自身大小4/默认对齐数4/对齐数4 ---偏移量为4
};//结构体1
S1大小为8
struct S2
{//偏移量为0
char a;//自身大小1/默认对齐数4/对齐数1 ---偏移量为0
int c;//自身大小4/默认对齐数4/对齐数4 ---偏移量为4
char b;//自身大小1/默认对齐数1/对齐数1 ---偏移量为8
};//结构体2
S2大小为12
对齐的原因:
有些CPU可以随意访问内存中的任意地址,但有些CPU只能访问特定的内存地址,不同的硬件平台具有的差异,如果不进行内存对齐会导致代码不具有移植性。
CPU 寻址存在一定的时间消耗,CPU 访问内存时并不是逐个字节访问的,而是以字长为单位访问的,若没有内存对齐则会出现结构体成员变量需要多次访问才能读取变量的问题,使用内存对齐是一种牺牲空间换取时间的方法。
指定系统默认对齐数
使用预处理指令
1. #pragma pack(show) 以警告信息的形式显示当前字节对齐的值.
2. #pragma pack(n) 将当前字节对齐值设为 n .
3. #pragma pack() 将当前字节对齐值设为默认值(VS编译器中的默认值是8) .
共用体内存对齐
对齐规则
- 共用体的大小至少是成员变量大小的最大值
- 若共用体的大小不是最大对齐数的整数倍,需要对齐到最大对齐数的整数倍
union U1
{
char a[6];
int c;
};
按照以上的对齐规则,成员变量最大的大小为6,所以该共用体的大小至少为6,而其最大对齐数为4,要共用体大小需要对齐到最大对齐数的整数倍,则大小应该为8