结构体对齐的几个问题浅析

来源:互联网 发布:淘宝卖家退货退款流程 编辑:程序博客网 时间:2024/06/07 13:35

1.关于结构体对齐

许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的起始地址的值是某个数k的倍数,这就是所谓的内存对齐,而这个k则被称为该数据类型的对齐模数(alignment modulus)。这种强制的要求一来简化了处理器与内存之间传输系统的设计,二来可以提升读取数据的速度。比如这么一种处理器,它每次读写内存的时候都从某个8倍数的地址开始,一次读出或写入8个字节的数据,假如软件能保证double类型的数据都从8倍数地址开始,那么读或写一个double类型数据就只需要一次内存操作。否则,我们就可能需要两次内存操作才能完成这个动作,因为数据或许恰好横跨在两个符合对齐要求的8字节内存块上。


2.第一个问题

#include "stdio.h"#pragma pack(4) struct student{unsigned char s1;unsigned char s2;unsigned int s3;unsigned int s4;}x;int main(){printf("%d\n" , sizeof(struct student));return 0;} 

VS2005以及gcc-4.4的输出均是12。

开始遇到这个问题的时候,觉得很奇怪,因为在我的想法里,应该是16才对,自己认为可能是设置有问题,于是加入了#pragma pack(4) ,可是结果还是12,于是各种baidugoogle

找到了这个(http://www.cnblogs.com/motadou/archive/2009/01/17/1558438.html)

结构体大小的计算方法和步骤
1)将结构体内所有数据成员的长度值相加,记为sum_a; 
2)将各数据成员为了内存对齐,按各自对齐模数而填充的字节数累加到和sum_a上,记为sum_b。对齐模数是#pragma pack指定的数值以及该数据成员自身长度中数值较小者。该数据相对起始位置应该是对齐模式的整数倍; 
3)将和sum_b向结构体模数对齐,该模数是#pragma pac指定的数值和结构体内部最大的基本数据类型成员长度中数值较小者。结构体的长度应该是该模数的整数倍。

  charshortintlongdoublelong doubleWindows长度124488模数124488Linux长度1244812模数124444

以上面的例子来说,sum_a = 10,数据成员s1放在相对偏移0处,之前不需要填充字节;s2同样不需要填充;数据成员s3为了内存对齐,根据“结构体大小的计算方法和步骤”中第二条原则,其对齐模数是4,之前需填充2个字节,所以sum_b=12,因为12是4的倍数,所以最终结果是12.


3.第二个问题

#include "stdio.h"#pragma pack(4) struct student{unsigned char s1:1;unsigned char s2:2;unsigned int s3:3;}x;int main(){printf("%d\n" , sizeof(struct student));return 0;} 



在VS2005下,运行结果是8,这个根据上面的规则很容易理解,但是在GCC下,运行结果是4,
这个应该是由于使用了位结构体造成的,GCC可能是做了一些优化。我个人觉得,VS2005把结构体对齐的优先级放在了位结构体优先级的前面,所以答案是8,而GCC将位结构体规则放在了前面,优先考虑位结构体。具体的猜测的根据,请看第三个问题。


4.第三个问题


#include "stdio.h"union{struct student{unsigned char s1:1;unsigned char s2:2;unsigned short s3:2;}x;unsigned short c;unsigned int d;}v;int main(){v.d=0;v.x.s1=0;v.x.s3=2;printf("%d\n",v.x);printf("%d\n",sizeof(v));return 0;} 

这段代码在VS2005中运行结果是131072  , 4

在GCC中的运行结果是16 , 4

131072 = (100000000000000000)b,在VS2005中,输出这样的答案,是因为对于short s3,已经使用了结构体对齐。

16 = (10000)b,说明在GCC中,对于short s3并没有进行结构体对齐,只是运用了位结构体的规则。

这里的区别需要注意一下。。。另外希望能有一个统一的标准,要不然这样确实很麻烦哎。


原创粉丝点击