c# 结构体 4字节对齐_零基础入门之结构体字节对齐

  • Post author:
  • Post category:其他


一、字节对齐的规则:

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编译器基本数据类型长度对照表

783516bc6310ecdac75b4da0f67f682b.png

实例参考:

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 = %dn",
  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

分享一些C语言相关的资料便于学习参考

结构体普及与应用

C语言玩转链表

必备Linux命令和C语言基础

释放潜能:学习效率提升、编程能力提升