现在的位置: 首页 > 综合 > 正文

深入C语言之字节对齐

2013年02月13日 ⁄ 综合 ⁄ 共 2034字 ⁄ 字号 评论关闭

Jason @ 2008-04-06 22:36

 

C程序设计中我们经常需要用到一种数据类型的长度(占内存的字节数),例如:
  int *p = NULL;
  p = (int *)malloc(10*sizeof(int));/*
sizeof(int)来的到int类型的长度*/
  
sizeof可得到C语言中数据类型的长度,对基本数据类型而言,结果值很容易理解,但当sizeof的操作对象是一个结构类型时意想不到
麻烦就来了,其结果值经常与我们设想的不一样.为什么呢?现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的
变量的访问可以从任何地址开始,但实际情况并非如此.一些平台对某些特定类型的数据只能从某些特定地址开始存取,这就需要各种
类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放.这就是所谓的字节对齐.字节对齐是为了提高CPU的读取效
.比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以
读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据.显然
在读取效率上下降很多.

  C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如intlongfloat等)的变量,也可以是一些复合数据类型
(如数组、结构、联合等)的数据单元.在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空 .各个成员按
照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同.

  先让我们看几个例子吧(32bit,x86环境,gcc编译器):设结构体如下定义:
struct A
{
    int a;
    char b;
    short c;
};
struct B
{
   char b;
   int a;
   short c;
};
  
现在已知32位机器上各种数据类型的长度如下:
char:        1(
有符号无符号同)          short:      2(有符号无符号同) 
int:          4(
有符号无符号同)          long:        4(有符号无符号同) 
float:        4                               double:8
  
那么上面两个结构大小如何呢?结果是:sizeof(strcut A)值为8sizeof(struct B)的值却是12
  
结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一个,B也一样;按理说A,B大小应该都是7
.之所以出现上面的结果就是因为编译器要对数据成员在空间上进行对齐.但然上面是按照编译器的默认设置进行对齐的结果,那么
我们是不是可以改变编译器的这种默认对齐设置呢,当然可以.例如:
#pragma pack (2) /*
指定按2字节对齐*/
struct C
{
   char b;
   int a;
   short c;
};
#pragma pack () /*
取消指定对齐,恢复缺省对齐*/
sizeof(struct C)
值是8
修改对齐值为1
#pragma pack (1) /*
指定按1字节对齐*/
struct D
{
   char b;
   int a;
   short c;
};
#pragma pack () /*
取消指定对齐,恢复缺省对齐*/
sizeof(struct D)
值为7

  在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间.一般地,可以通过下面的方法来改变缺省的对界条
件:
·
使用伪指令#pragma pack (n),C编译器将按照n个字节对齐.
·
使用伪指令#pragma pack (),取消自定义字节对齐方式.
另外,还有如下的一种方式:
· __attribute((aligned (n))),
让所作用的结构成员对齐在n字节自然边界上.如果结构中有成员的长度大于n,则按照最大成员的长度来
对齐.
· __attribute__ ((packed)),
取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐.
以上的n = 1, 2, 4, 8, 16... 第一种方式较为常见.

  那编译器是按照什么样的原则进行对齐的?先看四个重要的基本概念:
1.
数据类型自身对齐值:对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节.

2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值.
3.
指定对齐值:#pragma pack (value)时的指定对齐值value.
4.
数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值.
有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式.有效对齐值N是最终用来决定数据存放地址方式的
,最重要-->

作者:

抱歉!评论已关闭.