• 内存对齐


    结构体中的内存对齐:

           总结有两点记下:

           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.

  • 相关阅读:
    Java 面向对象(二)封装
    Java 面向对象(一)面向对象思想
    Java 字符串(二)字符串常用操作
    Java 字符串(一)字符串初始化
    JavaScript 流程控制(二)循环结构
    【剑指Offer-知识迁移能力】面试题58:翻转单词顺序
    【剑指Offer-知识迁移能力】面试题57.2:和为s的连续整数序列
    【剑指Offer-知识迁移能力】面试题57:合为s的两个数字
    【剑指Offer-知识迁移能力】面试题56:数组中只出现一次的两个数字
    【剑指Offer-知识迁移能力】面试题55.2:平衡二叉树
  • 原文地址:https://www.cnblogs.com/baiweiguo/p/2827216.html
Copyright © 2020-2023  润新知