C++之结构体内存对齐
内存对齐原因
首先要知道,cpu是把内存当作一块一块来读取的,块的大小可以是2,4,8,16个字节,这样内存不对齐就可能会导致每次读取数据需要读取两次,内存对齐之后读取一次就行,可以大大提高内存的访问速度。
结构体内存对齐原则
- 第一个成员在与结构体偏移量为0的地址处,排列在后面的成员其当前偏移量必须是当前成员类型的整数倍。
- 其他成员变量要对齐到对齐数的整数倍的地址处。对齐数=编译器默认的一个对齐数和该成员大小的较小值。VS默认对齐数8,gcc默认对齐数4。(这里就是偏移量的原因,插入缓冲区)
- 结构体总大小:最大对齐数(所有变量类型最大者和默认对齐参数取最小)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
- 如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再考虑当前类型以及最大结构体内类型
#include<algorithm>
using namespace std;
struct A
{
char a;
int b;
double c;
};
struct B
{
int b;
char a;
char c;
};
int main() {
cout << sizeof(A) << endl;//16
cout << sizeof(B) << endl;//8
return 0;
}
分析:
- 首先,第一个结构体中,第一个变量char类型占据1字节,偏移量为0,int 占据四字节,偏移量为int的整数倍,所以实际编译器会在第一个变量后面插入3字节缓冲区,现在共占据了8字节,第三个变量占据8字节,偏移量为double的整数倍,现在已经是double的整数倍了,bc之间不用插入缓冲区,现在总共占据16字节
- 最后,要根据结构体总大小对齐规则保证结构体占用的内存大小是最大对齐数的整数倍,此时最大对齐数是8,整数倍是16.
#include<algorithm>
using namespace std;
#pragma pack(2)
struct A
{
char a;
int b;
double c;
};
struct B
{
int b;
char a;
char c;
};
int main() {
cout << sizeof(A) << endl;//14
cout << sizeof(B) << endl;//6
return 0;
}
C++11
引入两个关键字alignas和alignof。其中alignof:计算出类型的对齐方式,alignas:指定结构体的对齐方式,不过若是小于自然对齐的最小单位,会被忽略这行代码。
参考:内存对齐规则之我见
结构体内存对齐