内存对齐

内存对齐是因为平台移植需求和性能优化考虑。硬件平台可能限制特定类型数据必须在特定地址访问,否则引发异常。对齐可以避免多次内存访问,提高效率。文章通过实例解释了内存对齐的规则和计算过程,展示了如何在结构体中进行内存填充以满足对齐规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内存对齐

内存地址对齐,是一种在计算机内存中排列数据(表现为变量的地址)、访问数据(表现为CPU读取数据)的一种方式,包含了两种相互独立又相互关联的部分:基本数据对齐结构体数据对齐

存在内存对齐原因:

1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;

某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2、性能原因:数据结构(尤其是栈)应该尽可能地在⾃然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存

问;而对齐的内存访问仅需要一次访问。


1、基本数据对齐
                 在X86,32位系统下基于Microsoft、Borland和GNU的编译器,有如下数据对齐规则:
                 a、一个char(占用1-byte)变量以1-byte对齐。
                 b、一个short(占用2-byte)变量以2-byte对齐。
                 c、一个int(占用4-byte)变量以4-byte对齐。
                 d、一个long(占用4-byte)变量以4-byte对齐。
                 e、一个float(占用4-byte)变量以4-byte对齐。
                 f、一个double(占用8-byte)变量以8-byte对齐。
                 g、一个long double(占用12-byte)变量以4-byte对齐。
                 h、任何pointer(占用4-byte)变量以4-byte对齐。

                64位系统下:
                 a、一个long(占用8-byte)变量以8-byte对齐。
                 b、一个double(占用8-byte)变量以8-byte对齐。
                 c、一个long double(占用16-byte)变量以16-byte对齐。
                 d、任何pointer(占用8-byte)变量以8-byte对齐。

       2、结构体数据对齐
       结构体数据对齐,是指结构体内的各个数据对齐。在结构体中的第一个成员的首地址等于整个结构体的变量的首地址,而后的成员的地址随着它声明的顺序和实际占用的字节数递增。为了总的结构体大小对齐,会在结构体中插入一些没有实际意思的字符来填充(padding)结构体。

       在结构体中,成员数据对齐满足以下规则:
a、第一个成员在结构体变量偏移量为0的地址处。
b、其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
  对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。
 VS中默认的值为8
  gcc中的默认值为4
c、结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的
整数倍。
d、如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,
结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。


#include<stdio.h>
int main()
{
	struct
	{
		char a;
		int b;
		short c;
		char d;
	}dataAlign;   
	struct 
	{
		char a;
		char d;
		short c;
		int b;
	}dataAlign2;
	printf("dataAlign:%d\ndataAlign2:%d\n",sizeof(dataAlign),sizeof(dataAlign2));
	return 0;
}
得到的结果如下:



      首先来看dataAlign,第一个成员等于结构体变量首地址,偏移量为0,第二个成员为int=4,为了满足规则b,需要在第一个成员之后填充3-byte,让它相对于结构体首地址偏移量为4,结合运行结果,可知&dataAlign.a = 0x01109140,而&dataAlign.b = 0x01109144,它们之间相隔4-byte,0x01109141~0x01109143三个字节被0填 充。第三个成员short=2,无需填充满足规则b。第四个成员char=1,也不需要填充。结构体总大小相加4 + 4 + 2 + 1 = 11。同样最后需要验证规则c,结构体中数据类型大小最大为第二个成员int=4,比VC默认对齐模数8小,故这个结构体的对齐模数仍然为4,显然11 mode 4 != 0,故为了满足规则c,需要在char后面填充一个字节,这样结构体变量dataAlign的总大小为4 + 4 + 2 + 2 = 12。

        再来看dataAlign2,第一个成员的地址等于结构体变量的首地址,第二个成员char类型,为了满足规则b,它相对于结构体的首地址的偏移量必须 是char=1的倍数,由于前面也是char,故不需要在第一个和第一个成员之间填充,直接满足条件。第三个成员short=2如果要满足规则b,也不需 要填充,因为它的偏移量已经是2。同样第四个也因为偏移量int=4,不需要填充,这样结构体总共大小为8-byte。最后来验证规则c,在VC中默认 的#pragma pack(n)中的n=8,而结构体中数据类型大小最大的为第四个成员int=4,故对齐模数为4,并且8 mode 4 = 0,所以满足规则c。这样整个结构体的总大小为8。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值