一、结构体内存对齐规则
1.第一个成员在结构体偏移量为0的地址处
2.其他成员变量要对齐到对齐数的整数倍地址处(对齐数= min(对齐数,变量大小))
(VS下默认对齐数为8,也可以自定义对齐数,#pragma pack(x),x为对齐数)
3.结构体总大小为:最大对齐数的整数倍(最大对齐数是所有变量类型最大者与对齐数的较小值)
4.对于嵌套结构体,需要对齐到自己最大对齐数的整数倍处。结构体的整体大小就是所有最大对齐数(包括嵌套结构体的对齐数)的整数倍
样例1
class A {int a;char b;
};
sizeof(A)=8
变量a在偏移量为0的地址处,占用前4个地址,对齐数为4(遵循规则1);变量b大小为1字节,VS默认对齐数为8,所以变量b的对齐数为1,可以存放到第4个地址处(遵循规则2);结构体的总体大小需要是最大对齐数的整数倍,变量a的对齐数为4,变量b的对齐数为1,最大对齐数为4,因此结构体的总体大小需要是4的整数倍,而当前结构体只占用了5个字节,所以还需要补3个字节给结构体(遵循规则3);因此结构体的最终大小为8。
样例2
class B {char a;int b;
};
sizeof(B)=8
变量a在偏移量为0的地址处,占用第0个地址,对齐数为1(遵循规则1);变量b大小为4个字节,VS默认对齐数为8,所以变量b的对齐数为4,不能直接存放到第1个地址处,需要补3个字节在变量a后,再将变量b存放到第4个地址处(遵循规则2);最终结构体共占用8个字节,最大对齐数为4,所以无需再补字节给结构体(遵循规则3);因此结构体最终大小为8。
二、为什么要进行结构体内存补齐?
原因1:不同硬件平台规定CPU一次读取字节数不同,可能一次读取2、4、8、16、32个字节
原因2:CPU只能从其读取字节数的整数倍地址处开始读
以CPU一次读取4字节为例,CPU只能从4的整数倍地址处开始读。对于class B,如果没有内存对齐,想要读取变量b的数据,CPU先从0地址处读取4个字节,只能读取到变量b的前3个字节,CPU再从4地址处读取4个字节,才能读取到变量b的第4个字节,需要读取两次,效率低下。
而经过内存对齐后,CPU只需要从4地址处读取一次,即可得到变量b的全部字节。
三、补充:自定义对齐数
#pragma pack(x) x为对齐数
#pragma pack(1)//将对齐数设置为1
class A {int a;char b;
};class B {char a;int b;
};int main()
{cout << sizeof(A) << endl;//5cout << sizeof(B) << endl;//5return 0;
}