快速且正确地理解C++内存对齐机制
C++内存对齐机制
对不同的编译器,我们首先定义一个最小有效对齐值pack。对gcc来说,这个值为4,可以通过预编译命令#pragma pack(n)
来修改。
内存对齐要求每个成员变量相对于结构体首地址的偏移量恰好为min(pack, sizeof(该变量))
的整数倍。同时,也要求整个结构体的长度恰好为pack值的整数倍,否则会在最后一个成员变量后添加空白字节。
则C++的内存对齐可以用伪代码描述为:
size_current = 当前成员大小
if size_current < pack :
while(存在下一个成员变量 and size_current + 下一个成员变量大小 <= pack):
把下一个成员挤进这段空间
size_current += 下一个成员变量大小
if(依然存在下一个成员变量 and size_current + 下一个成员变量大小 > pack):
填充空白字节直到当前段填满为pack的整数倍
else if(没有下一个成员变量 and size_current % pack != 0):
填充空白字节直到当前段填满为pack的整数倍
CPU的视角中,是只存在基础类型的。什么意思呢?也就是说,即使在结构体A中嵌套了结构体B,其计算内存对齐时我们并不考虑结构体B有多大,而是考虑结构体B中基本类型的大小
为什么C++会采取内存对齐机制
C++的内存对齐机制的目的是让CPU能够在尽可能短的时间内获取到数据,从而提高整体性能。假如不采取内存对齐机制,则访问数据时还需要对成员变量的基本类型进行判断从而计算出正确的偏移量。
使用例♂
#include <iostream>
#pragma pack(2)
struct stct1
{
char a;
int b;
char c;
};
struct stct2
{
char a;
char b;
int c;
};
int main() {
stct1 var1;
stct2 var2;
printf("%d\n", sizeof(var1));
printf("%d\n", sizeof(var2));
}
// 输出8和6
对stct1:
- a变量占用1byte,而pack值为2byte,因此需要填充1byte空白,最终占用2byte
- b变量占用4byte,恰好为两倍pack值,最终占用4byte
- c变量同a变量相同,最终占用2byte
对stct2:
- a变量占用1byte,而恰好b变量也占用1byte,填满了正好一个pack值,故最终占用2byte
- c变量占用4byte,恰好为两倍pack值,最终占用4byte