快捷搜索: 王者荣耀 脱发

快速理解内存对齐以及#pragma pack

一、内存对齐目的与原理 1、内存对齐的目的 假如没有内存对齐机制,数据可以任意存放,现在一个int变量存放在从地址1开始的联系四个字节地址中,该处理器去取数据时,要先从0地址开始读取第一个4字节块,剔除不想要的字节(0地址),然后从地址4开始读取下一个4字节块,同样剔除不要的数据(5,6,7地址),最后留下的两块数据合并放入寄存器.这需要做很多工作。 现在有了内存对齐的,int类型数据只能存放在按照对齐规则的内存中,比如说0地址开始的内存。那么现在该处理器在取数据时一次性就能将数据读出来了,而且不需要做额外的操作,提高了效率。 2、原理 在32位编译环境下默认4字节对齐,在64位编译环境下默认8字节对齐。 例如:如下结构体:

struct s {
          
   
	int a;
	double b;
	char c;
};

(1)在64位编译环境下,sizeof(s)=24。 解析: 首先你得知道各数据类型的字节长度: char 1 int 4 double 8 那么其在内存中的存储如下:

从0的位置开始储存,int有4字节,默认8字节对齐,则下一个数据从第8位开始,double型正好8位,于是char接着从第16为开始,因为char型占一个字节,所以要补充7个字节空位。如果有下一个数据,将从第24位开始存储。

(2)在32位编译环境下,sizeof(s)=16。 么其在内存中的存储如下: 一共占16个字节。

二、修改对齐字节的方法:#pragma pack(对齐系数) 对齐系数:如1,2,4,8,16。如前所述:在不定义#pragma pack()的时候,在32位编译环境下默认4字节对齐相当于#pragma pack(4),在64位编译环境下默认8字节对齐相当于#pragma pack(8)。 例如有如下结构体:

#include<stdio.h>
#pragma pack(8)
struct s {
          
   
	int a;
	double b;
	char c;
}s;
int main()
{
          
   
	printf("sizeof size = % d
", sizeof(s));
}
测试结果
#pragma pack(1)-----------sizeof(s)=13
#pragma pack(2)-----------sizeof(s)=14
#pragma pack(4)-----------sizeof(s)=16
#pragma pack(8)-----------sizeof(s)=24
#pragma pack(16)-----------sizeof(s)=24

可以看到#pragma pack(8)和#pragma pack(16)时,结构体所占内存一样,这与我们之前的不一致。这是因为存在以下几条对其规则:

  1. 数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
  2. 结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
  3. 结合1、2可推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

参考资料/文献:

经验分享 程序员 微信小程序 职场和发展