Chinaunix首页 | 论坛 | 博客
  • 博客访问: 75854
  • 博文数量: 13
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 164
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-06 22:57
文章存档

2013年(13)

我的朋友

分类: C/C++

2013-03-12 09:50:15

在说明对齐问题之前请看下面代码:

点击(此处)折叠或打开

  1. #include "stdio.h"

  2. void main(int argc, char *argv)
  3. {
  4.    
  5.     struct A
  6.     {
  7.      int a;
  8.      char b;
  9.      short c;
  10.     };

  11.     struct B
  12.     {
  13.      char b;
  14.      int a;
  15.      short c;
  16.     };
  17.     
  18.     printf("sizeof(int)=%d sizeof(char)=%d sizeof(short)=%d\n",sizeof(int),sizeof(char),sizeof(short));
  19.     
  20.     printf("sizeof(A) =%d sizeof(B)=%dn",sizeof(struct A),sizeof(struct B));
  21. }

在运行代码之前,请思考下输出值应该是多少?如果你的答案是8 12,那么恭喜你!
那么两个看似相同的结构体,大小差异为什么会这么大?这都是归因于计算机的字节对齐。
所谓字节对齐:
计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放
下面引入几个关于对其的概念:
1.数据类型的字对齐:对于char 自对其为1字节,对于short 自对齐值为2字节,对于int float double自对齐值为4字节。
2.结构体(位域的自对齐值为其成员中自对齐最大的值。
所谓自对齐值即 变量的起始地址%自对齐值==0.
下面分析下struct B:
假定结构体的开始地址为0x00,那么b的存储空间为0x00 ,0x00 %1==0,a的存储地址为多少呢?由于a需自对齐,必须使a的起始%4==0,同时必须紧靠b,容易得出a的起始地址为0x04。0x01-——0x03为结构体的填充字节,c的起始地址为0x08。根据上面的推断,那B的长度应该是10为什么会是12呢?请看概念2,结构体类型也有自对齐,是成员中自对齐的最大值既4。假如存在结构体B数组,为了保证第二个元素的自对齐,那么第一个元素的长度必须是12,既sizeof(struct B)==12.

既然系统有默认的对齐方式,那么对齐的方式在C语言中是否可以改变呢?答案是肯定的:
3.可以用#pragma pack(value)改变对齐的值。
4.当使用了#pragma pack(value)时,数据成员,结构体的对齐值为自对齐值和指定对齐值中的较小值
请看实列:

点击(此处)折叠或打开

  1. #include "stdio.h"

  2. void main(int argc, char *argv)
  3. {
  4.     struct A
  5.     {
  6.      int a;
  7.      char b;
  8.      short c;
  9.     };

  10.     struct B
  11.     {
  12.      char b;
  13.      int a;
  14.      short c;
  15.     };
  16.     
  17.     printf("sizeof(A) =%d sizeof(B)=%d\n",sizeof(struct A),sizeof(struct B));

  18.     #pragma pack (2) //指定为2字节对齐
  19.     struct c
  20.     {
  21.      char b;
  22.      int a;
  23.      short c;
  24.     };
  25.     printf("sizeof(C)=%d\n",sizeof(struct c));
  26.     #pragma pack ()           //取消2字节对齐

  27.     #pragma pack (1)        //指定1字节对齐
  28.     struct D
  29.     {
  30.      char b;
  31.      int a;
  32.      short c;
  33.     };
  34.     printf("sizeof(D)=%d\n",sizeof(struct D));
  35.     #pragma pack ()         //取消指定的1字节对齐

  36. }
思考下C D的长度应该分别为多少?
下面分析下 C,D结构体的长度:由于自定了对齐方式为2,根据规则4 char int short 的有效自对齐值分别为1 2 2,结构体的有效自对齐由4变为2,故假如C的起始地址为0x00,b的地址为0x00 a的起始地址为0x02,c的起始地址为0x06.
由于D指定对齐长度为1,那么char int short 以及结构体的有效自对齐都变为1,当b的起始地址为0x00时,a的地址为0x01,c的起始地址为0x05。


阅读(2016) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~