内存对齐

结构体中的内存对齐:

       总结有两点记下:

       1.结构体的长度一定是最长数据元素大小的整数倍;

       2.各成员变量存放的起始位置 相对于 结构体的地址 的偏移量 必须为该变量的类型所占字节数的倍数。

 

默认情况下,为方便对结构体内元素的访问和管理,

1)当结构体内元素的长度 都小于 处理器的位数的时候,便以结构体里面最长的数据元素的大小为对齐单元,即 结构体的长度一定是最长数据元素大小的整数倍

2)如果结构体内存在长度 大于 处理器位数的元素,那么就以处理器的位数为对齐单位。(一般情况下,不会出现此种情况,CPU 32位)

 

CPU优化规则大致规则如下:对于n字节的元素(n = 2,4,8.……),它的首地址若能被 n 整除,才能获得最好的性能。

设计编译器的时候可以遵循这个原则:对于每一个变量,可以从当前位置向后找到第一个满足这个条件的地址作为首地址。

 

为了提高CPU的存储速度,VC对一些变量的起始地址做了“对齐”处理。

在默认情况下,VC规定各成员变量存放的起始地址 相对于 结构的起始地址的 偏移量 必须为该变量的类型所占用的字节数的倍数。

一般情况下,记住有下滑线的两行文字就可以了。

 1 struct S1
 2 {
 3     char a;  // 1*** 1111 11111111
 4     int b;
 5     double c;   
 6 };
 7 struct S2  
 8 {
 9     double a; //11111111 111111111 1*******
10     double b;
11     char c;
12 };
13 int main()
14 {
15     int i = sizeof(S1); // S1 的大小为:16
16     int j = sizeof(S2); // S2 的大小为:24
17     return 0;
18 }

 

 

复杂类型的对齐方式

      复杂类型(如结构)的默认对齐方式是它最长成员元素的对齐方式。

例子:

 

 1 #include <cstdio>
 2  struct S1
 3  {
 4      char a;  //a 默认按 1 字节对齐,其首地址 偏移量为 1 的倍数
 5      long b;  //b 默认按 4 字节对齐,其首地址 偏移量为 4 的倍数
 6  };           //S1 内存中布局为: 1*** 1111,*表示编译器自动填
 7               //        充的空字节,1 表示不是编译器自动填充的字节
 8  
 9  struct S2
10  {
11      char c;       // 首地址偏移量 为 0000
12      struct S1 d;  // 首地址偏移量 为 0004,对齐方式 按 其元素最长的长度 即4
13      _int64 e;     //long long e; //首地址偏移量为 0008
14  };                // 布局: 1*** 1***1111 **** 11111111
15  
16  int main()
17  {
18      int i = sizeof(S1);
19      int k = sizeof(S2);
20      printf("%d %d \n",i,k);// i:8,k:24
21      return 0;
22  }

 

 其中结构体S2中S1的默认对齐是按 4 个字节,即其首地址 的偏移量是 4 的倍数,这样能最小化长度。

 三点重要:

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

2.复杂类型(如结构)的默认对齐方式是它的最长成员元素的对齐方式,这样当成员是复杂类型时,可以最小化长度

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

 

 另外:VC中提供了 #pragma pack(n) 来设定变量以 n 字节对齐。屏蔽掉默认的对齐方式。

n 字节对齐就是说变量存放起始地址的偏移量有两种情况:

1)如果 n 大于等于 该变量所占用的字节数,偏移量必须满足默认的对齐方式,此时,设定不起作用

2)如果 n 小于该变量所占用的字节数,那么偏移量 为 n 的倍数,不满足默认对齐方式。

 此时,结构体的总大小变为:1)若n 大于所有成员变量类型的长度,结构体总大小为最大变量长度的整数倍

                                      2)否则为 n 的倍数。

 

 1 #pragma pack(push)   //保存对齐状态
 2 #pragma pack(4)     //设定为4个字节
 3 
 4 struct test
 5 {
 6     char a;         // 按 1 个字节的对齐方式
 7     double b;       // 按 4 个字节的对齐方式
 8     int c;          // 按 4 个字节的对齐方式
 9 };
10 #pragma pack(pop)   //恢复对齐状态
11 
12 int main()
13 {
14     int i = sizeof(test);
15     return 0;
16 }

设定为 4 个字节的对齐方式后 内存布局为: 1*** 11111111 1111,大小为 16

按默认的对齐方式的布局: 1******* 11111111 1111**** ,大小为 24.

posted @ 2012-12-21 12:16  winko  阅读(185)  评论(0编辑  收藏  举报