什么是内存对齐
内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个数据单元安排在适当的位置上。
出现原因( 老生常谈的两句话 )
- 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
- 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
对齐规则
- 第一个成员放在偏移量(offset)为0的地方。
- 以后的每个成员的偏移量:
min(#pragma pack()指定的数值,当前成员的大小)
的倍数中。 - 每个成员对齐后,本身也要对齐,整体的偏移量:min(#pragma pack()指定的数值,结构体最大数据成员的大小)。
关于 #pragma pack
- 通过
#pragma pack(n)
来设定变量以n字节对齐方式 - n字节对齐就是说变量存放的起始地址的偏移量有两种情况
- 如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式 。
- 果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式 。
- 32位系统默认为4,64位系统默认为8。
举个例子🌰
#include<stdio.h> #pragma pack(4) struct Node{ char a; char b; int c; }; int main(void){ printf("%d",sizeof(struct Node)); return 0; }
首先看规则1,成员变量a的偏移量为0,所以a占1个字节。
- 对于成员变量b,
min(4,sizeof(char))
的值为1,所以偏移量为1的倍数,所以b也占一个字节且不补全。 - 对于成员变量c,
min(4,sizeof(int))
的值为4,所以偏移量为4的倍数,也就是说c只能从4,8,16开始放,因此在b后面要空开两个字节,再放成员变量c。 - 目前为止,abc加起来总共占了8个字节,然后要确定
sizeof(struct Node)
,还要知道min(4,sizeof(int))
的值为4,所以无需再补全。 最后
sizeof(struct Node)
的值就为8。
#include<stdio.h> #pragma pack(4) struct Node{ char a; int c; char b; }; int main(void){ printf("%d",sizeof(struct Node)); return 0; }