C语言深度解剖读书笔记(3.结构体中内存对齐问题)

转自 http://blog.csdn.net/mbh_1991/article/details/10241785

很多人都觉得内存对齐这个问题很难,很不好算,总算错,其实我想说只要你画一画就没那么难了。好了,进入正题。

本节知识点:

1.结构体为什么要内存对齐(也叫字节对齐):

其实我们都知道,结构体只是一些数据的集合,它本身什么都没有。我们所谓的结构体地址,其实就是结构体第一个元素的地址。这样,如果结构体各个元素之间不存在内存对齐问题,他们都挨着排放的。对于32位机,32位编译器(这是目前常见的环境,其他环境也会有内存对齐问题),就很可能操作一个问题,就是当你想要去访问结构体中的一个数据的时候,需要你操作两次数据总线,因为这个数据卡在中间,如图:

在上图中,对于第2个short数据进行访问的时候,在32位机器上就要操作两次数据总线。这样会非常影响数据读写的效率,所以就引入了内存对齐的问题。

另外一层不太重要的原因是:某些硬件平台只能从规定的地址处取某些特定类型的数据,否则会抛出硬件异常。

2.内存对齐的规则:

    a.第一个成员起始于0偏移处

    b.每个成员按其类型大小和指定对齐参数n中较小的一个进行对齐

    c.结构体总长度必须为所有对齐参数的整数倍

    d.对于数组,可以拆开看做n个数组元素

3.来几个小例子,画画图,有助于理解:

第一个例子,代码如下:

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. struct _tag_str1  
  3. {  
  4.     char a;  
  5.     int b;  
  6.     short c;  
  7. }str1;  
  8.   
  9. struct _tag_str2  
  10. {  
  11.     char a;  
  12.     short c;  
  13.     int b;  
  14. }str2;  
  15.   
  16. int main()  
  17. {  
  18.     printf("sizeof str1 %d\n",sizeof(str1));  
  19.     printf("sizeof str2 %d\n",sizeof(str2));  
  20.     return 0;  
  21. }   
输出的结果分别是:str1为12    str2为8,分析的过程如下图:

看图很自然就知道了str1为12个字节,str2为8个字节。

第二个例子,上面的那个例子有好多问题还没有考虑到,比如说上面的那个例子在8字节对齐,和4字节对齐的情况都是一样的。结构体中嵌套结构体的内存对齐怎么算,所以就有了这个例子,代码如下:

[cpp]  view plain copy
  1. #include <stdio.h>  
  2.   
  3. #pragma pack(8)  
  4. //#pragma pack(4)  
  5. struct S1  
  6. {  
  7.     short a;  
  8.     long b;  
  9. };  
  10.   
  11. struct S2  
  12. {  
  13.     char c;  
  14.     struct S1 d;  
  15.     double e;  
  16. };  
  17.   
  18. #pragma pack()  
  19.   
  20. int main()  
  21. {  
  22.     struct S2 s2;  
  23.       
  24.     printf("%d\n"sizeof(struct S1));  
  25.     printf("%d\n"sizeof(struct S2));  
  26.     printf("%d\n", (int)&(s2.d) - (int)&(s2.c));  
  27.   
  28.     return 0;  
  29. }  
在Dev c++中,默认的是8字节对齐。我们分析下在4字节对齐的情况下输出的是,S2是20,S1是8,分析如图:


在4字节对齐的情况中,有一个问题值得注意:就是图中画1的地方。这里面本应short是可以上去的。但是对于结构体中的结构体一定要十分警惕,S1是一体的,short已经由于long进行了内存对齐,后面还空了两个字节的内存,其实此时的short已经变成了4个字节了!!!即结构体不可拆,不管是多少字节对齐,他们都是一体的。所有的圈都变成了叉。所以说结构体只能往前篡位置,不能改变整体。

我们在分析一些8字节对齐的情况,如图:


同样,到这里又有一个字节对齐的原则要好好重申一下:就是以什么为对齐参数,首先我们要知道编译器或者自己定义的是多少字节对齐的,这个数为n。然后我们要看这个结构体中的各个数据类型,找到所占字节数最大的类型,为m。如果n大于m,就以m为对齐参数,比如说一个4字节对齐的结构体中都是short,那这个结构体以什么为对齐参数,当然是2了,如果m大于n,就以n为对齐参数,比如说在4字节对齐的情况下的double类型。

 以上就是我对内存对齐的小总结,最最想要说明的就是两大段红色的部分。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值