分享

零基础入门之结构体字节对齐

 人生如戏ds3xoc 2019-11-13

  一、字节对齐的规则:

  1、一般设置的对齐方式为1,2,4字节对齐方式。结构的首地址必须是结构内最宽类型的整数倍地址;另外,结构体的每一个成员起始地址必须是自身类型大小的整数倍(需要特别注意的是windows下是这样的,但在linux的gcc编译器下最高为4字节对齐),否则在前一类型后补0;这里特别提到的是数组一定要注意,而且在一些编程的技巧中,我们可以使用数组强制字节达到对齐的目的。这在网络编程中是很常见的。

  举例:比如CHAR型占用空间为1字节,则其起始位置必须可被1整除。INT为4字节,其起始位置必须被4带队,依次类推。(我们假定类或结构体的起始位置为0位置,其实编译器是在开辟空间时,会寻找起始位置可被结构内最宽类型整除的地址做为开始地址,因此我们可以假定其为0值,因为这0值可以被任意的类型整除。)

  2、结构体的整体大小必须可被对齐值整除,默认4(结构中的类型大小都小于默认的4)。

  3、结构体的整体大小必须可被本结构内的最宽类型整除。(其实和上一条是一样的,但这里独立出来,起注意作用。比如结构体里的有DOUBLE,那么结构的大小最后必须可被8整除)

  注意:GCC不是这样,就是最高只能被4整除。此为32位系统,64为系统也会采用8整除的方式。否则(2、3条),编译器会在结构的最后添充一定的特定字符来补齐。

  struct T

  {

  char ch;

  double d ;

  };

  此结果强调为32系统在VC中是16个字节,GCC中为12个字节。64位依旧是16个字节

  4、对于结构体内嵌套结构体的形势,规定是必须按照基本数据类型来定义,而不能以嵌套结构大小来做为上三种使用的基准。(总结)结构体可以处理成char类型。

  二、举例:

  struct A

  {

  int a;

  char b;

  short c;

  }; //8

  struct B

  {

  char b;

  int a;

  short c;

  }; // 12

  struct C

  {

  double t;

  char b;

  int a;

  short c;

  }; //24

  struct D

  {

  char b;

  double t;

  int a;

  short c;

  };//24

  在VC中,SIZEOF这四个结构体,分别为:8、12、24、24;

  我们先谈第一个,(说明一下,在考虑结构体大小时,我们基本可以忽略起始地址的问题,因为这个编

  译器会自动为我们做好,见上面的说明),结构体内首先是一个INT的4字节,起始地址假定为0,整除4,其小于等于默认的4字节对齐且0为4(INT的占用空间)的整数倍,所以,其占四个字节;其后为起始地址为5,空间为1个字节的CHAR,小于4且5为1(CHAR占用空间)的整数倍,故占用1个字节,然后是一个起始地址为5占2个字节的SHORT,其小于4,但5不为2位数,故补齐一个字节,从第6个字节开始,占2字节空间。所以共占用4+1+1(补)+2=8;8/4=2;整除,故占用8字节空间。

  再谈第2个,CHAR不用解释,占有一个字节空间,且可以被0地址整除。而INT则占4字节空间,所以其必须在CHAR后补齐3字节,到第四个字节,才是INT的真正地址。SHORT也不用说,所以共占有:1+3(补)+4+2=10个字节,但10不能整除4,所以要在结构体最后补齐2字节。故实际占有10+2= 12个字节。

  谈第三个,C结构体只是在B结构体前加了一个DOUBLE,其它都一样,按说应该是20个字节啊,但注意我们上面规则的第3条。必须是最宽类型的整数倍,一定要分清,所以得补齐到24,D结构体类似,不再讲。

  Linux系统32位与64位GCC编译器基本数据类型长度对照表

  实例参考:

  GNU C扩展的__attribute__ 机制被用来设置函数、变量、类型的属性,其用得较多的是处理字节对齐的问题。

  __attribute__ 的语法为:

  __attribute__ ((语法列表))参数aligned(number) [number为最小对齐的字节数]是用得较多的一个。

  另一个是参数packed 表示“使用最小对齐”方式,即对变量是字节对齐,对于域是位对齐。

  #include

  struct A{

  char a; //1Byte

  int b; //4B

  unsigned short c;//2B

  long d; //4B

  unsigned long long e; //8B

  char f; //1B

  };

  struct B{

  char a;

  int b;

  unsigned short c;

  long d;

  unsigned long long e;

  char f;

  }__attribute__((aligned));

  struct C{

  char a;

  int b;

  unsigned short c;

  long d;

  unsigned long long e;

  char f;

  }__attribute__((aligned(1)));

  struct D{

  char a;

  int b;

  unsigned short c;

  long d;

  unsigned long long e;

  char f;

  }__attribute__((aligned(4)));

  struct E{

  char a;

  int b;

  unsigned short c;

  long d;

  unsigned long long e;

  char f;

  }__attribute__((aligned(8)));

  struct F{

  char a;

  int b;

  unsigned short c;

  long d;

  unsigned long long e;

  char f;

  }__attribute__((packed));

  struct H{

  char a;

  double b;

  };

  int main(int argc, char **argv)

  {

  struct A a;

  struct B b;

  struct C c;

  struct D d;

  struct E e;

  struct F f;

  printf("A = %d, B = %d, C = %d, D = %d, E = %d, F = %d, H = %d\n",

  sizeof(struct A), sizeof(struct B), sizeof(struct C), sizeof(struct D), sizeof(struct E), sizeof(struct F),sizeof(struct H));

  return 0;

  }

  结果:

  $ ./aligned32

  A = 28, B = 32, C = 28, D = 28, E = 32, F = 20, H = 12

  $ ./aligned64

  A = 40, B = 48, C = 40, D = 40, E = 40, F = 24, H = 16

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多