2017年计算机等级考试二级C++辅导:字节对齐问题

时间:2017-05-04 17:38:00   来源:无忧考网     [字体: ]

  规则:

  1 、数据成员对齐规则:结构 (struct)( 或联合 (union)) 的数据成员,第一个数据成员放在 offset 为 0 的地方,以后每个数据成员的对齐按照 #pragma pack 指定的数值和这个数据成员自身长度中,比较小的那个进行。

  2 、结构 ( 或联合 ) 的整体对齐规则:在数据成员完成各自对齐之后,结构 ( 或联合 ) 本身也要进行对齐,对齐将按照 #pragma pack 指定的数值和结构 ( 或联合 ) 数据成员长度中,比较小的那个进行。

  3 、结合 1 、 2 可推断:当 #pragma pack 的 n 值等于或超过所有数据成员长度的时候,这个 n 值的大小将不产生任何效果。 使用指令#pragma pack (n),编译器将按照 n个字节对齐。使用指令#pragma pack (),编译器将取消自定义字节对齐方式。在#pragma pack (n)和#pragma pack ()之间的代码按 n个字节对齐。

  struct s1

  {

  int a;

  char b;

  short e;

  int c;

  };

  struct s2

  {

  int a;

  char b;

  int c;

  short e;

  int d;

  };

  1字节对齐 为 11 和 15

  2字节对齐 为 11 和 16

  4字节对齐 为 12 和 20

  8字节对齐 为 12 和 20

  16字节对齐 为 12 和 20

  看如下例子:

  #pragma pack(8)

  struct TestStruct4

  {

  char a;

  long b;

  };

  struct TestStruct5

  {

  char c;

  TestStruct4 d;

  long long e;

  };

  #pragma pack()

  问题:

  A) sizeof(TestStruct5)=?

  B) TestStruct5的 c 后面空了几个字节接着是 d ?

  TestStruct4中,成员 a 是 1字节,默认按 1字节对齐,指定对齐参数为 8,这两个值中取 1,a 按 1字节对齐;成员 b 是 4个字节,默认是按 4字节对齐,这时就按 4字节对齐,所以sizeof(TestStruct4)应该为 8。

  TestStruct5 中,c 和 TestStruct4 中的 a 一样,按 1字节对齐,而 d 是个结构,它是 8个字节,它按什么对齐呢?对于结构来说,它的默认对齐方式就是它的所有成员使用的对齐参数中的一个, TestStruct4的就是 4。所以,成员 d 就是按 4字节对齐。成员 e 是 8个字节,它是默认按 8字节对齐,和指定的一样,以它对到 8字节的边界上。这时,已经使用了12个字节了,所以又添加了 4个字节的空,从第 16个字节开始放置成员 e。这时,长度为24,已经可以被 8(成员 e 按 8字节对齐)整除。这样,一共使用了 24个字节。内存布局如下(*表示空闲内存,1表示使用内存,单位为 1byete) :

  a b

  TestStruct4的内存布局:1***, 1111

  c TestStruct4.a TestStruct4.b d

  TestStruct5的内存布局: 1***, 1***, 1111, ****, 11111111

  这里有三点很重要:

  首先,每个成员分别按自己的方式对齐,并能最小化长度。

  其次,复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。

  然后,对齐后的长度必须是成员中的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。

  补充一下:

  对于数组,比如:char a[3],它的对齐方式和分别写 3个 char 是一样的,也就是说它还是按 1 个字节对齐。如果写:typedef char Array3[3];Array3 这种类型的对齐方式还是按 1 个字节对齐,而不是按它的长度。