首先用一段代码演示内存对齐
#include <stdio.h>
struct ak{
short c;
int b;
char i;
}a1;
struct bk{
int b;
short i;
char a;
}a2;
int main()
{
printf("%d %d ",sizeof(a1),sizeof(a2));//12 8
return 0;
}
看到上面的代码大家一定很好奇,为什么相同的元素,只是改变了元素的位置,计算出的结果就完全不相同了,这就是内存对齐导致的。
什么是内存对齐?
在计算机中,内存是按字节划分的,而CPU在读取内存数据时,并不是一字节一字节读取的,实际上是按块来读取的。
块的大小可以是1,2,4,8,16等等,块的大小也称为内存访问粒度。
而内存对齐是将特定的数据类型按照一定的规则摆放在内存上,以此提高CPU访问内存的速度。
为什么要内存对齐?
平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
性能原因:经过内存对齐后,CPU的内存访问速度大大提升。
在32位设备上,int x,因为CPU对内存的读取操作是对齐的,如果X的地址不是4的倍数,那么读取这个X,需要读取两次共8个字节,然后还要将其拼接成一个int,这比存取内存对齐过的X要麻烦很多。
对齐方式?
每个特定平台上的编译器都有自己默认的“对齐系数”,程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中n就是你要指定的“对齐系数”。
举例验证
同样的我们用上面的程序来验证#pragma pack(n)内存对齐
#include <stdio.h>
#pragma pack(2)
struct ak{
short c;
int b;
char i;
}a1;
struct bk{
int b;
short i;
char a;
}a2;
int main()
{
printf("%d %d ",sizeof(a1),sizeof(a2));//8 8
return 0;
}
当对齐的系数n为2时,只需要结构体成员类型可以整除2,所以打印出的结果都为8。
对齐原则
1.在32位系统中,最大类型长度为成员类型长度最大值和4取较小者。
2.内存对齐后结构体对象内存大小为最大类型长度的倍数
3.结构体对象中成员的起始地址为当前类型长度的倍数