内存对齐

来源:互联网 发布:win10摄像头拍照软件 编辑:程序博客网 时间:2024/06/06 12:42

内存对齐

内存地址对齐,是一种在计算机内存中排列数据(表现为变量的地址)、访问数据(表现为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。
0 0