内存对齐
一、内存对齐的原因
大部分的参考资料都是如是说的:
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
二、内存对齐的规定:
三、计算
#include <stdlib.h>
#include <iostream>
using namespace std;
int main() {
struct AA {
char a;
char b;
char c;
};
cout << sizeof(AA) << endl;
system("pause");
}
这个比较简单,可以根据上面的表格可以直接计算出来。
来个有点难度的
#include <stdlib.h>
#include <iostream>
using namespace std;
int main() {
struct AA {
char a;
int b;
char c;
};
cout << sizeof(AA) << endl;
system("pause");
}
猜猜结果会是多少? 会是 5 吗??
来详细了解一下:
实际上会如图所示吗???
当以如图的方式存放数据时,系统访问char a 时,只需读取一个字节,但当访问 int b 的时候,先要读取一个字节,在读取四个字节,才能读到int b的值。这样系统在访问数据时要先判断各个数据的字节大小,在进行读取,这样就会浪费时间。为了节省时间,会如下的方式去存储数据:
在存储数据时,会对char a 补充 3 个字节,这样在访问 char a、int b 时,每次只需读取 4 个字节就可以,以一种空间换时间方式来提高效率。
当如图存放数据之后,整个结构体的大小为 9 个字节。这与计算输出的结果不符(还记得,通过程序计算的大小为 12 个字节),这是为什么吗??
还记得前面说的内存对齐的第四条规则吗??
4.结构体总大小必须是对齐模数的整数倍。
在上面给出了一个表格,上面有常见数据类型的模数,那我们如何确定一个结构提的模数呢???
其实结构体的模数等于其内部模数最大的成员类型的模数
struct AA {
char a;
int b;
char c;
};
对于结构体AA来说,他的模数就是 4。
则该结构体的大小必须是 4 的整数倍,所以在最后还会补充 3 个字节(如下图)。
这样结构体AA的大小就是 12 个字节。
在添加点难度:
#include <stdlib.h>
#include <iostream>
using namespace std;
int main() {
struct AA {
char a;
int b;
char c;
};
struct BB {
char d;
int e;
double f;
AA g;
};
cout << sizeof(BB) << endl;
system("pause");
}
先来看看答案:
来分析一下:
到结构AA,来看看结构体AA的情况:
所以接下来应该如下图:
由图可知 结构体BB一共占据32个字节的内存,到这里就完了吗??
还记得 内存对齐的第四条规则吗??
4.结构体总大小必须是对齐模数的整数倍。
结构体BB的模数为多少呢??
因为double e 的模数最大为 8 ,所以BB的模数也为8。32 是 8 的倍数,所以结构体BB只占 32 个字节。
四、自定义模数大小
可以通过#pragma pack() 自定义模数的大小。
#include <stdlib.h>
#include <iostream>
using namespace std;
#pragma pack(1)
int main() {
struct AA {
char a;
int b;
char c;
};
struct BB {
char d;
int e;
double f;
AA g;
};
cout << sizeof(BB) << endl;
system("pause");
}
将模数的大小自定义为 1 后,运行结果如下:
当模数大小定义为 2 时,运行结果如下:
可以自己去试试画图理解。