设为首页 加入收藏

TOP

C语言的struct的数据成员对齐(一)
2014-02-08 12:43:14 来源: 作者: 【 】 浏览:281
Tags:语言 struct 数据 成员

  一、引言:

  sizeof是c语言中的一个运算符,用来求某个变量或者类型的长度,CSDN有篇文章介绍sizeof的特点介绍的比较详细,我写这篇文章主要是介绍struct的数据成员对齐。C语言的struct成员对齐与操作系统有关,在window与linux上的表现不同,先来看一个例子:

  1 #include

  2 typedef struct{

  3 int num1;

  4 int num2;

  5 double num3;

  6

  7 }A;

  8 typedef struct{

  9 int num1;

  10 double num3;

  11 int num2;

  12 }B;

  13

  14 int main(void) {

  15 printf("A:%d\n",sizeof(A));

  16 printf("B:%d\n",sizeof(B));

  17 return 0;

  18 }

  二、windows的对齐情况

  上面这段程序在windows下执行打印的是:

  A:16

  B:24

  为什么数据成员一样,只是成员的顺序不同,导致结构体所占的空间会不同,这就是数据对齐的原因,为了提高存储器的访问效率,避免读一个成员数据访问多次存储器,操作系统对基本数据类型的合法地址做了限制,要求某种类型对象的地址必须是某个值K的整数倍(K=2或4或8)。Windows给出的对齐要求是:任何K(K=2或4或8)字节的基本对象的地址都必须是K的整数倍。在上面的示例中,num1和num2为int占4个字节,num3为double占8了字节,结构体A、B的数据对齐情况分别如下:

  上面的是结构体A的对齐情况,下面的是结构体B的对齐情况,图中的灰色部分为对齐填充部分,不代表有效数据。可以看到A的分布很紧凑,没有留下空隙,而B中,有两段空隙,因为数据A不需要填充就能满足K(这里K=4、8)字节的对象的起始地址是K的整数倍了。而B中,第一个数据成员是num1,大小为四个字节,接下来的是num3,大小为8个字节,num3不能紧接在num1的后面,因为4不是8的整数倍,因此需要填充4个字节,这样num3的起始地址就在8上,满足要求,之后的num2接在num3后,起始地址为16。有人会问,为什么B占用的是24个字节,而不是20个字节,从上面的图中,也看出,用20个字节刚好装下了num1、num2、num3这三个元素,并且这三个元素都满足了对齐要求,为什么num2后面还要填充4个字节 事实上,如果只有一个B对象,20字节确实是满足对齐要求的,但如果我们声明一个类型为B的数据:B b ,每个B对象只用20字节,则其数据偏移情况如下:

  可以看到,b 的num3的起始地址是28,不满足8的整数倍的要求,这就是B为什么要24字节的原因,为了所有的数据满足”任何K(K=2或4或8)字节的基本对象的地址都必须是K的整数倍“的要求,必须是结构体的整体大小必须是最大的K的整数倍。

  三、linux的对齐情况

  以上是windows的对齐要求,如果在linux上执行前面的示例,输出A、B所占的字节数都是16。Linux的对齐要求是:2字节类型的数据(如short)的起始地址必须是2的整数倍,而较大(int *,int double ,long)的数据类型的地址必须是4的整数倍。linux的对齐要求比windows宽松,这样会更加充分的利用存储空间,但是访问效率没有window好。linux下结构体B的对齐情况如下:

  这里是针对32位的系统,对于X86-64,linux与windows一样,要求K字节的数据类型是K的倍数。

  以上是对struct的数据对齐的简单介绍,我想,这个数据对齐可以出两个面试题,一个是已知道结构体定义,求成员的起始地址和结构体大小;另一个是,已知结构体定义,如何排列成员变量的顺序,使得整个结构体占有的存储空间最小。

  四、计算结构体的大小和各个成员的起始地址

  这个题目是比较简单的,只要把对齐要求理解了,我们只前往后处理每一个变量,只要当前放入的变量满足对齐要求,然后递归求后门的变量,直接上代码了:

  #include

  #include

  #include

  #define MAX 100

  char *vars[MAX];//保存变量名

  int lens[MAX];//保存变量的字节长度

  int start[MAX];//保存变量的起始地址

  int ALIGN;

  /*********扫描成员变量和长度,每一组输入由变量名和长度组成**********/

  int scanfStruct(){

  char var[20],*p;

  int len;

  int index = 0;

  printf(">>");

  while(scanf("%s %d",var,&len) && var[0] != '$'){

  p = (char *)malloc(strlen(var));

  strcpy(p,var);

  vars[index] = p;

  lens[index] = len;

  printf(">>");

  // printf("%s:%d\n>>",vars[index],lens[index]);

  index ++;

  }

  return index;

  }

   

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C中数据量常见习题集合 下一篇c语言连接mysql原代码实例

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: