分析编译条件产生结构体内存字节布局

1、测试环境

操作系统:WIN7(X86),

位数:32

编译器:C1(vc++)

内存字节顺序:Small Endian

2、对齐规则

         结构体的内存布局依赖于CPU、操作系统、编译器及编译时的对齐选项。结构体内部成员的对齐要求,结构体本身的对齐要求。最重要的有三点:

         1)成员对齐。对于结构体内部成员,通常会有这样的规定:各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。但是也可以看到,有时候某些字段如果严格按照大小紧密排列,根本无法达到这样的目的,因此有时候必须进行padding。各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节编译器会自动填充也就是padding。

         2)然后,还要考虑整个结构体的对齐需求。ANSI C标准规定结构体类型的对齐要求不能比它所有字段中要求最严格的那个宽松,可以更严格。实际上要求结构体至少是其中的那个最大的元素大小的整数倍。因为有时候我们使用的是结构体数组,所以结构体的大小还得保证结构体数组中各个结构体满足对齐要求,同时独立的结构体与结构体数组中单个结构体的大小应当是一致的。

         3)编译器的对齐指令。VC中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数。

3、为何要内存对齐

         http://www.ibm.com/developerworks/library/pa-dalign/

         因为处理器读写数据,并不是以字节为单位,而是以块(2,4,8,16字节)为单位进行的。如果不进行对齐,那么本来只需要一次进行的访问,可能需要好几次才能完成,并且还要进行额外的合并或者数据分离。导致效率低下。更严重地,会因为cpu不允许访问unaligned address,就会报错,或者打开调试器或者dump core,比如sun sparcsolaris绝对不会容忍你访问unalignedaddress,都会以一个core结束你的程序的执行。所以一般编译器都会在编译时做相应的优化以保证程序运行时所有数据都是存储在'aligned address'上的,这就是内存对齐的由来。

         在'Data alignment: Straighten up and fly right'这篇文章中作者还得出一个结论那就是:"如果访问的地址是unaligned的,那么采用大粒度访问内存有可能比小粒度访问内存还要慢"。

4、测试代码

struct Test
{
    char a;
    int b;
    short c;
    double d;
};

int main(int argc, char* argv[])
{
    int m = 0;
    printf("&m=[%08x]\n", &m);
	
    struct Test t;         
    printf("sizeof(Test)=%d\n", sizeof(struct Test));
    printf("&a=[%08x]\n", &t.a);
    printf("&b=[%08x]\n", &t.b);
    printf("&c=[%08x]\n", &t.c);
    printf("&d=[%08x]\n", &t.d);
	
    int n = 0;
    printf("&n=[%08x]\n", &n);
}


5、测试条件1:struct memberalignment=8

         sizeof(Test)= 24.


解释

         1)、0x10 % 1 == 0(其中1=sizeof(char)),满足对齐方式,a占用1个字节;

         2)、0x11 % 2 != 0(其中2=sizeof(short)),不满足对齐方式,需要补足3个字节才能使偏移量变为4(满足对齐方式),b占用4个字节;

         3)、0x18 % 4 == 0(其中4=sizeof(int)),满足对齐方式,c占用2个字节;

         4)、0x1a % 8 != 0(其中8=sizeof(double)),不满足对齐方式,需要补足6个字节才能使偏移量变为32(满足对齐方式),d占用8个字节。

6、测试条件2:struct memberalignment=4

         sizeof(Test)= 20.


说明

struct Test

{

char a;               //偏移量为0,满足对齐方式,a占用1个字节;

int b;                  //下一个可用的地址的偏移量为1,不是sizeof(int)=4的倍数,需要补足3个                               //字节才能使偏移量变为4(满足对齐方式),因此VC自动填充3个字节,                             //b存放在偏移量为4的地址上,它占用4个字节。

short c;              //下一个可用的地址的偏移量为8,是sizeof(short)=2的倍数,满足short的                                 //对齐方式,所以不需要VC自动填充,c存放在偏移量为8的地址上,它占                                    // 用2个字节。

double d;         //下一个可用的地址的偏移量为10,不是sizeof(double)=8的倍数,需要补足                     // 6字节才能使偏移量变为16(满足对齐方式),因此VC自动填充6个字节,                      // d存放在偏移量为16的地址上,它占用8个字节。

};

         所以该结构总的大小为:sizeof(Test)为1+3+2+2+4+8=20。其中总的有3+2=5个字节是VC自动填充的,没有放任何有意义的东西。

 

7、总结


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值