结构体对齐规则

来源:互联网 发布:淘宝相似问题怎么看 编辑:程序博客网 时间:2024/06/07 04:06

结构体对齐 , #pragma pack(4),结构体的长度(sizeof)

(一个没有考虑周详的位段结构体中,可能存在大量“缝隙”)

1.       对齐规则

1.        实际对齐值决定系统一次划分内存的字节数量。系统为变量分配内存时,必须先划分够变量数据类型需要的对齐空间(对齐模数,字节单位)。

2.       结构体的实际对齐值为结构体中最大的数据类型的长度A与系统规定的对齐值B两者中间较小的那个值Min(A,B)决定。如果变量的数据类型长度大于实际对齐值,为这个变量分配对齐空间时,系统连续进行多次分配以满足对齐空间的要求。

3.       完全容纳概念:

1.1   宽度比对齐空间小的变量不能分散在多个对齐空间中(注意:是对齐空间,不是字节),如果前一个对齐空间剩余的大小不足以容纳当前变量,则当前变量从下一个对齐空间开始,前一个对齐中间的不足部分,由系统自动填充(padding)。

1.2   如果变量的宽度大于对齐空间的宽度(即全局对齐空间pack定义小于结构体中最大宽度的变量大小),则该变量的地址相对于结构体首地址的偏移量,必须是对齐空间大小的整数倍,即宽度大于对齐空间的变量,其内存分配不能从一个对齐空间的中间开始,必须从一个对齐空间的头开始。例:

_tagS的大小为16,而不是12或者其它,因为对齐空间大小是8(字节),s1虽然只占了1个字节,但是剩下的7字节不够容纳s2的8个字节,所以s2必须从新的对齐空间开始分配。(上例中,如果pack为4,则_tagS的大小则为12;如果pack为2,则_tagS的大小则为10;如果pack为1,则_tagS的大小则为9)

1.3   位段变量可以跨越字节,但是不能跨越对齐空间。例如:

S2结构体中的位段和为64,刚好为8个字节,但是sizeof(s2)值并不是8,而是12,这就是因为变量受到对齐空间约束的原因:变量不能跨越对齐空间。由于第一个对齐间空间不能同时容纳a,b,所以第一个对齐空间中并没有b的一部分内容,b从第二个对齐空间开始占位,b,c一共占用了第二个对齐空间,第二个对齐空间中只剩下2位空位,不能容纳d,所以d再分配一个对齐空间4字节。(此结构体因为所有变量数据类型相同,所以对齐值由结构体中的数据类型决定)。最后的结果是:第一个对齐空间中空余1位,第二个对齐空间中空余2位,第三个对齐空间中空余29位。

4.       共用对齐空间:当一个对齐空间中可以容纳几个变量时,这些变量可以共用对齐空间。任何变量都不能跨越对齐空间

Ø  如果一个对齐空间足够容纳多个数据类型(注意:不是位段),则允许一个对齐空间中存在不同数据类型的变量,否则,要开辟新的对齐空间。例如:(实际对齐值为4)

不同数据类型的a,b共用一个对齐空间,因为变量不能跨越对齐空间,所以c独占一个对齐空间,d独占一个对齐空间,结构体长度值为12。

Ø  使用位段时,有且只有相同数据类型的位段变量可以共用内存字节!如果数据类型不相同,即使前一个变量中剩余的位空间完全可以容纳后面几个位段变量,下一个变量的位空间分配也是从下一个字节开始分配,如果本对齐空间里的剩余字节数能够容纳下一个变量的数据类型(注意:是数据类型,不是变量位段数),则下一个变量和本变量共用一个对齐空间;否则,下一个变量从一个新的对齐空间开始。

例子:(因为系统对齐值8大于结构体中最大数据类型的长度4=sizeof(__int32),所以实际对齐值为4,而不是明确指定的8。)

a,b共用一个对齐空间,c独点一个对齐空间,虽然第二个对齐空间的剩余位段数8=32-24还完全可以容纳d的位段数4,但是由于c,d的数据类型不一样,所以d从下一个字节开始分配。由于c的数据类型(__int32)完全占据一个对齐空间,下一个字节是从新的对齐空间开始的,所以d从一个新的对齐空间开始占用。所以sizeof(s1)的值为12。

如果例子改为:

由a,b共同占一个对齐空间,第一个对齐空间被a,b的数据类型占据,c从一个新的对齐空间开始占用,实际对齐值为4,所以第二个对齐空间大小为4字节,被c的数据类型占用两字节后,还剩下的两字节能够完全容纳d的数据类型(__int8),所以d的数据类型虽然和c的数据类型不一样,但是d也不必从新的对齐空间开始占用,而是和c共用一个对齐空间。所以sizeof的值为8,比上面的例子少使用一个对齐空间。

一点引用:http://blog.csdn.net/hikaliv/archive/2009/06/03/4239352.aspx

2.       Win32平台下的对齐策略

1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internaladding);

3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节(trailingpadding)。

 

类的内存分布对齐规则与结构体的类似,只是缺少了字段概念。

其一,C++语言保证“出现在derived class中的base class suboject有其完整性”;

其二,derivedclass的对齐数 = min(指定的全局对齐数,max(base class的对齐数,derived class的对齐数))

可参见:http://blog.csdn.net/pathuang68/archive/2009/04/24/4106016.aspx