Chinaunix首页 | 论坛 | 博客
  • 博客访问: 60479
  • 博文数量: 8
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 82
  • 用 户 组: 普通用户
  • 注册时间: 2014-11-04 17:00
文章分类

全部博文(8)

文章存档

2016年(5)

2015年(3)

我的朋友

分类: C/C++

2016-03-05 15:54:29

转载请注明出处:http://blog.chinaunix.net/uid-30008524-id-5663357.html

C里面的结构体和联合体都涉及到字节对齐的问题。
首先说一下结构体。结构体内存布局的规则是
1.以成员中最大的数据类型为步长分配内存块给结构体
2.每个成员存储的起始地址必须是自身类型的整数倍
比如说一个结构体
struct A
{
    char a;    
    int b;
    char c;
    short d;
};
A里面最大的类型是int,4个字节,所以以4个字节为单位分配内存块给A。
先分配一个4个字节内存块给A,把A.a放进去,内存是这样的:(每个数字代表一个字节,1是有数据存放,*是没有数据存放)
1***
a
再放b,b有4个字节,放不下了,增加一个内存块,由于规则2,b必须在4的倍数地址开始存储,所以b放在第二个内存块中,放进来后内存是这样的:
1***    1111
a       b
再分配一个内存块放c,内存是这样的
1***    1111    1***
a       b      c
再放d,2个字节,根据规则2,d放在最后两个字节
1***    1111      1*11
a       b      c  d
所以sizeof(A)=12

联合体
联合体的内存布局规则是
1.以成员中最大的数据类型为步长分配内存块给结构体(这条规则跟结构体一样)
2.能装下最大成员的最小内存
比如说一个联合体
union B
{
    char a[10];
    int 4;
};
按照规则2,至少要分配10字节内存才能放下a,然后根据规则1,每个内存块4个字节,B占用的内存要大于等于10,同时是4的倍数的最小值,所以B占用12字节。
我们来写个小程序验证一下。

点击(此处)折叠或打开

  1. #include "stdio.h"
  2. #include "string.h"
  3. struct A
  4. {
  5.     int a;
  6.     char b;
  7.     short c;
  8. };
  9. union B
  10. {
  11.     int a;
  12.     char b;
  13.     short c;
  14. };
  15. int main()
  16. {
  17.     A a = {1,2,3};
  18.     A c = {1,2,3};
  19.     if(memcmp(&a,&c,8)==0)
  20.         printf("same");
  21.     else
  22.         printf("diff");

  23.     memset(&a,0,sizeof(a));
  24.     memset(&c,0,sizeof(c));
  25.     a.a = 1;a.b = 2;a.c = 3;
  26.     c.a = 1;c.b = 2,c.c = 3;

  27.     if(memcmp(&a,&c,8)==0)
  28.         printf("same");
  29.     else
  30.         printf("diff");
  31.     B b;
  32.     b.a = 1;b.b = 2;b.c = 3;
  33.     return 0;
  34. }
在19行设置断点,然后运行,我们来看一下


a占用了8个字节,然后a.a放在内存低位,占4个字节,值为0x01,a.b值为0x02,放在第五个字节,a.c从第七个字节开始,占用两个字节,值为0x03.
内存布局简化为:
1111  1*11
注意那个未填充的*,显示是0x86,其实是随机的
我们对比一下a和c的空隙的地方


一个是0x86,一个是0x72.虽然a和c用同样的值去初始化,但其内部不是一模一样的,所以第20行用memcmp去对比a和c,会打印“diff”,程序继续运行,memset把a和c清零,再对a和c赋一样的值,此时再memcmp,得到是是“same”,因为空隙的地方已经被清零了。

再来看一下联合体b,b.a=1,b.b=2,b.c=3.对每个成员都赋值一遍


可以看到b占用4个字节,就是成员最大的数据类型int的大小。其内部值是3,就是b.c的值。
再看里面每个成员和b自身的起始地址


发现它们地址都是一样的,联合体的所有成员都和联合体共享一个起始地址,也就说,新的赋值会冲掉旧的赋值,所以b里面只存储了3,前面赋的1和2都被冲掉了。
阅读(3431) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~