结构体在内存中对齐

 刚刚完成一个文件的迁移程序,其中遇到了结构体对齐的问题,所以拿出来说说,与各位博友们分享。

我的程序很简单,就是把之前通过一个结构体 fwrite 到文件 A 里的内容读出,然后转给另一个结构体保存。程序是简单,但我担心的是之前 结构体 fwrite 到文件 A 的程序对齐结构体规则是怎样的?一定要知道它吗 ? 当然了,如果那个程序结构体是按照 1 对齐写入的,我的程序结构体是按照 4 对齐读入,那不就糟了!

      这里我引入结构体对齐的概念,也可以说是内存对齐了。为什么要内存对齐呢,就是方便 CPU 寻址了,具体原因大家要参考计算机体系结构了。先看一个内存对齐的例子:

      struct example1{

           char a;

           double b;

           long l;

};

      struct example2{

           char a;

           long l;

           double b;

};

大家算算结构体大小,初次接触的博友可能对答案有点惊讶, VC 编译, sizeof 后结果分别是: 24 , 16 。 同样是的结构体,成员换了顺序,大小就不同了。其实内存对齐有个规则,只要知道了,就 OK 。那么以下 5 点是关键

1.          内存对齐与编译器设置有关,首先要搞清编译器这个默认值是多少

2.          如果不想编译器默认的话,可以通过 #pragma pack(n) 来指定按照 n 对齐

3.          每个结构体变量对齐,如果对齐参数 n( 编译器默认或者通过 pragma 指定 ) 大于该变量所占字节数 (m) ,那么就按照 m 对齐,内存偏移后的地址是 m 的倍数,否则是按照 n 对齐,内存偏移后的地址是 n 的倍数。也就是最小化长度规则

4.          结构体总大小 : 对齐后的长度必须是成员中最大的对齐参数的整数倍。最大对齐参数是从第三步得到的。

5.          补充:如果结构体 A 中还要结构体 B ,那么 B 的对齐方式是选它里面最长的成员的对齐方式

所以计算结构体大小要走三步,首先确定是当前程序按照几对齐 ( 参照 1 , 2 点 ) ,接着计算每个结构体变量的大小和偏移 ( 参照 3 , 5) ,最后计算结构体总大小(参照 4 )。

      先算算 example1 吧,假设编译器是以 16 对齐的

      1 .确定按照几对齐 : 16;

      2 .确定每个成员的偏移: a 占一个字节, 16>1, 按照 1 对齐,起始位置 0 , 0%1 = 0 ,那么 a 就存在 0 位置; b 占 8 个字节, 16>8 ,按照 8 对齐,起始位置就不能是 1 了,因为要按照 8 对齐,所以最近的偏移起始位置是 8 , 8%8 =0, 那么 b 就存在位置 8-15 的位置; l 占 4 个字节, 16>4 ,按照 4 对齐,起始位置 16 , 16%4=0 ,那么 l 就存在位置 16-19 的位置。所以结构体从 0 到 19 一共占用 20 个字节

      3 .结构体总大小:成员中最大的对齐参数是 b 的 8 对齐,所以 20 % 8!=0, 24 刚好。

      真的很搞!同理计算 example2 应该是 16 ;

     再举个结构体嵌套的例子吧,

#pragma pack(push)

#pragma pack(8)

struct test1{

      int a;

      char b;

      int c[20]

long l;

} ;

struct test2{

      char a1;

      char a2;

      struct test1 t1;

      double b1;

}

#pragma pack(pop)

先计算 test1, 8 对齐, a 占用 0-3 , b 占用 4 , c 占用 8 - 87 , l 占用 88 - 91 ,一共 92 个字节。成员中最大的对齐参数是 int 了 92%4=0;

再计算 test2, a1z 占用 0 , a2 占用 1 , t1 呢, 92%2!=0, 2-92 , b1 占 96 到 103 ;一共 104 个字节,成员中最大的对齐参数是 double 了 104%8=0; 所以是 104.


      那关于我文章开头提到的那个文件转换,我现在只要知道原始程序是按照什么对齐的,然后在新程序中指定按照几对齐就可以了,哈哈!    

转自:http://www.cppblog.com/iuranus/archive/2009/01/06/71388.html       
      
      有的地方有遗漏,请各位指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值