标签:
为什么需要字节对齐?
计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。
字节对齐的细节和编译器实现相关,一般满足三个准则:
1)结构体首地址是最宽成员大小的倍数。
2)结构体每个成员相对于结构体首地址的偏移量(offset)都是当前成员大小的整数倍,
如有需要编译器会在成员之间加上填充字节(internal padding);
3)结构体的总大小为最宽成员大小的倍数,不足编译器则在最后一个成员后面填充字节。
基本类型指像char、short、int、float、double这样的内置数据类型,数据宽度指其sizeof的大小。
结构体中包含结构体时:
寻找最宽成员时要把内部的结构体打散来看。
确定复合类型成员的偏移位置时则是将复合类型作为整体看待
举例说明:
struct S1{char c; int i;}; struct S3{ char c1; S1 s; char c2; };
注意:偏移多少是指前面有多少个。
S1的最宽简单成员的类型为int
S3在考虑最宽简单类型成员时是将S1“打散”看的, 所以S3的最宽简单类型为int
这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除
c1的偏移量为0
s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8
偏移量为4,c1与s之间便需要3个填充字节
而c2与s之间就不需要了,所以c2的偏移量为12
算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节
最后得到sizeof(S3)的值为16
总结:
结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:
sizeof(struct)=offsetof(lastitem)+sizeof(lastitem)+sizeof(trailingpadding)
编译器的pack指令可以调整结构体对齐的方式
#pragmapack(n)
n为字节对齐数,其取值为1、2、4、8、16,默认是8
offsetof(item)=min(n,sizeof(item))
#pragmapack(push)//将当前pack设置压栈保存 #pragmapack(2)//必须在结构体定义之前使用 struct S1{ char c; int i; }; struct S3{ char c1; S1 s; char c2; }; #pragmapack(pop)//恢复先前的pack设置
标签:
原文地址:http://www.cnblogs.com/siqi/p/4657893.html