结构体的内存对齐问题

2016-12-04 13:11 阅读 774 次 评论 0 条

为什么要内存对齐?

1.平台问题(移植问题):不是所有的硬件平台都能访问任意地址上的任意数据的,某些硬件平台只能在某些地质处取某些特定类型的数据,否则跑出硬件异常。

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

结构体的内存对齐规则

1.第一个成员在结构体变量偏移量为0的地址处。

2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。其中对齐数 = 编译器默认的对齐数与该成员大小的较小值。vs默认是8,linux默认是4。

3.结构体总大小为最大对齐数的整数倍。

4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

设置默认对齐数

#pragma pack(value)   value为指定的对齐数。

#pragma pack()    取消指定对齐,恢复缺省对齐。

实例

上面这道简单的结构体的大小是多少呢?有一部分人会响亮的答出:13.那么恭喜你,答错了。这道题的正确答案是16.接下来我为大家分析一下:首先我们设置的默认对齐数为8,在结构体A中,int a作为结构体的第一个成员,对齐数为0,占4个字节,char b为第二个成员,对齐数为自身大小1与默认对齐数8的较小者,则为1,1+4 = 5,是对齐数1的整数倍,合理。第三个成员的大小为8与默认对齐数8取较小者为8,则5+8=13,最后总的大小应该是结构体中最大对齐数8的整数倍,则13会补全为16.

这次我们将默认对齐数设置为4,重新看一道题。在结构体A中,int a为第一个成员,对齐数为0,自身大小为4字节,不需要对齐,第二个成员为char b,对齐数为自身大小1与默认对齐数4的较小者1,4+1 = 5,5是对齐数1的整数倍,合理。第三个成员为int c[10],对齐数为自身大小40与默认对齐数4的较小者4,5+40=45,45不是对齐数4的整数倍,所以补齐到能整除4,45+3=48可以整除,最后一个成员为char *d,为一个指针,对齐数为自身大小4与默认对齐数4的较小者4,48+4=52,52可以整除最大对齐数4,则最终的答案为:52.

这次我们看个稍微难点的,结构体内嵌套结构体的例子。我们设置的默认对齐数为4,所以struct A与上一个例子一样,A占52个字节。主要看struct B,首先第一个成员int a1对齐数为0,大小为4个字节,第二个成员为char b1,对齐数为自身大小1与默认对齐数4的较小者1,4+1=5,5能够整除对齐数1,合理。第三个成员为double c1,对齐数为自身大小8与默认对齐数4的较小者4,5+8=13,13不能整除对齐数4,补齐到13+3=16,。第四个成员为struct A obj,对齐数为自身大小52余默认对齐数4的较小者,16+52=68,68能够整除4,合理。第五个成员为struct A*objp,对齐数为自身大小4与默认对齐数4的较小者4,68+4=72,72能够整除4,合理。第六个成员为struct A objarr[2],对齐数为自身大小52*2与默认对齐数4的较小者4,72+52*2=176,176可以整除4,合理。最后一个成员为char *d1,对齐数为自身大小4与默认对齐数4的较小者4,176+4=180,180可以整除最大对齐数4,则最终答案为:180.

版权声明:本文著作权归原作者所有,欢迎分享本文,谢谢支持!
转载请注明:结构体的内存对齐问题 | 术与道的分享
分类:编程素养 标签:, ,
1024do.com导航_术与道导航平台

发表评论


表情