内存对齐
现代计算机体系中CPU按照双字、字、字节访问存储内存,字是计算机进行数据处理和运算的单位,若未经一定规则的对齐,CPU的访址操作将会异常的复杂,所以现代编译器中都会对内存进行自动对齐。
数据成员对齐
结构体 struct 中的成员在内存中的分配是连续的,struct 内的首地址就是 struct 内第一个数据成员的地址,即 struct 内第一个数据成员离 struct 开始的距离 offset = 0。
对齐规则:
- 结构体第一个成员的偏移量(offset)为0,以后每个成员相对于结构体首地址的 offset 都是该成员大小与有效对齐值中较小那个的整数倍,如有需要编译器会在成员之间加上填充字节;
- 结构体的总大小为 有效对齐值 的整数倍,如有需要编译器会在最末一个成员之后加上填充字节;
- 结构体内类型相同的连续元素将在连续的空间内,和数组一样。
类型长度
sizeof的基本作用是判断数据类型或者表达式的长度(字节数)。
(注意:sizeof不是一个函数,而是一个C++中的关键字)
64位Visual Studio 2017环境下,C++内置类型长度:
cout << sizeof(char) << endl; // 1
cout << sizeof(short) << endl; // 2
cout << sizeof(int) << endl; // 4
cout << sizeof(long) << endl; // 4
cout << sizeof(long long) << endl; // 8
cout << sizeof(double) << endl; // 8
规则总结
连续申明的变量是否可以在内存中连续存储(即不填充字节),由变量长度之和是否超出一个块(有效对齐值个字节构成一个块,例如,8个字节为1个块)决定。
例如(8字节对齐):
struct
{
int a; // 4
char b; // 1
double c; // 8
}; // 16
int a 占4字节,char b占1字节,加起来为5个字节,不超过1个块,可以连续存储。double c 占8个字节,加起来13个字节,超过1个块,double c 在下一个块中存储。所以,最后存储情况为:4字节 int a,1字节 char b,3字节填充,8字节 double c,共16字节。
struct
{
char a;
double c;
}st;
cout << sizeof(st) << endl; // 16
内存对齐系数
#pragma pack的主要作用就是改变编译器的内存对齐方式,#pragma pack(n) 的作用是改变编译器的对齐系数,n 值可取(1,2,4,8,16),默认8字节对齐。