标签:
现代计算机的内存空间是以Byte为单位划分的,理论上对内存中数据的访问可以从任何地址开始,但实际上对特定类型变量的访问经常是在特定的地址开始。为了达到这个目的,就需要各类型的数据按照一定的规则在内存空间上排列,这即为内存对齐(Memory Alignment)。
对以下两个例子:
struct A { int ival; char cval; short sval; };
和
struct B { short sval; int val; char cval; };
sizeof(struct A)的结果为8, sizeof(struct B)的结果为12。其中int类型的长度为4,char的长度为1,short的长度为2。若按理论,sizeof(struct A)和sizeof(struct B)的结果都应该为7。但由于内存对齐原则,它们的结果并不一致。
至于内存对齐的对齐值,对于各种数据类型,即为其自己的长度;对于结构体或类,为其成员中对齐值最大的那个成员。所以对结构体而言,除了成员自身需要对齐外,成员之间还需按照结构体的对齐值对齐。
对以上两例子的分析如下,struct A在内存中的排列如下:
0x0000 |
0x0001 |
0x0002 |
0x0003 |
0x0004 |
0x0005 |
0x0006 |
0x0007 |
struct A的对齐值为其成员中对齐值最大的那个,即ival,为4。其成员存储在内存中时,是按顺序排列的。即先存储cval,然后是cval,最后为sval。
其中,第一个成员ival的长度为4,存储在0x0000~0x0003;第二个成员cval的长度为1,存储在0x0004;第三个成员sval长度为2,理论上应该存储在0x0005~0x0006,但由于short类型需对齐,实际存储的地址为0x0006~0x0007。在这里地址0x0005并未存储任何内容。
而struct B在内存中的排列则如下:
0x0000 |
0x0001 |
0x0002 |
0x0003 |
0x0004 |
0x0005 |
0x0006 |
0x0007 |
0x0008 |
0x0009 |
0x000A |
0x000B |
struct B的对齐值为4。其成员存储在内存中的顺序为sval,ival,cval。其中,sval存储在0x0000~0x0001,ival存储在0x0004~0x0007,cval存储在0x0008。由于结构体本身也需根据其自身对齐值圆整(即结构体成员变量占用的总长度应为结构体自身对齐值的整数倍),故0x0009~0x000B也会被占用。
综上可知,内存对齐即是变量按照其自身的对齐值在内存空间中找寻特定的地址进行存储。对于其对齐值N,即表示对齐在N上。也就是说此变量的“存放起始地址 % N == 0”。
通常并不需要考虑内存对齐,因为编译器会选择适合目标平台的对齐策略。但若需改变对齐策略,也可通过预编译指令通知编译器改变对齐方法。预编译指令#pragma pack(value)即为指定对齐值,其中value为需要指定的对齐值,若value置空,则恢复缺省对齐。
若指定了特定的对齐值,那么在变量成员的自身对齐值,结构体或类的自身对齐值后,则增加了一个指定对齐值。对于这三个对齐值,采取的策略为选择自身对齐值和指定对齐值中较小的那个作为有效对齐值。
#pragma pack(2) struct B { short sval; int ival; char cval; }; #pragma()
对于之前的struct B,若指定对齐值为2,则其在内存中的排列如下:
0x0000 |
0x0001 |
0x0002 |
0x0003 |
0x0004 |
0x0005 |
0x0006 |
0x0007 |
其中sval存储在0x0000~0x0001,ival存储在0x0003~0x0006,cval存储在0x0007,总长度为8。
本例采用的是x86_64和GCC实现。
标签:
原文地址:http://www.cnblogs.com/0xceff/p/4264988.html