• 内存对齐--面试常问问题和笔试常考问题


    1.内存对齐的意义

    C++ 内存对齐的主要意义可以简练概括为以下几点:

    1. 提高访问效率:内存对齐可以使数据在内存中以更加紧凑的方式存储,从而提高了数据的访问效率。处理器通常能够更快地访问内存中对齐的数据,而不需要额外的字节偏移计算。

    2. 硬件要求:许多硬件平台要求数据按照一定的对齐规则存储,否则可能会导致性能下降或者错误。不符合硬件要求的数据存储方式可能会引发总线错误或性能降低。

    3. 结构体和类的正确性:在C++中,结构体和类中的成员变量通常按照编译器的默认对齐方式进行排列,以确保数据的正确访问和存储。手动调整对齐方式可以保证数据的正确性。

    4. 跨平台开发:内存对齐可以确保数据在不同平台上的一致性。这对于跨平台开发非常重要,因为不同的硬件架构可能有不同的对齐要求。

    5. 节省内存:内存对齐可以减少内存碎片,从而节省内存空间。当数据按照对齐要求存储时,不会出现因为填充字节而浪费内存的情况。

    总之,C++ 内存对齐的主要意义在于提高访问效率、符合硬件要求、确保数据的正确性、支持跨平台开发以及节省内存空间。通过遵循对齐规则,可以充分利用硬件的性能优势,并确保程序在不同平台上的可移植性和正确性。

    2.对齐原则


    原则1 :数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在
    offiset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身
    长度中,比较小的那个进行。(先偏移到那个对齐标准数的指定倍数,在进行加上本身)
    原则2:结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进
    行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的
    那个进行。
    原则3 :结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元
    素大小的整数倍地址开始存储。

    3.默认对齐值

    默认对齐值:
    Linux默认#pragma pack(4)
    window默认#pragma pack(8)
    注:可以通过预编译命令#pragma pack(n) , n=1,2,4,8,16来改变这一系数,其中的n就是指定
    的“对齐系数”。

    例题1:

    1. #include
    2. #include
    3. #include
    4. #pragma pack(1)
    5. using namespace std;
    6. struct AA
    7. {
    8. int a; //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    9. char b; //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    10. short c; //长度2>1,按1对齐,偏移量提升到2的 倍数6,存放位置区间[5,6]
    11. char d; //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]
    12. //整体存放【0-7】 位置中,共八个字节。
    13. };
    14. int main()
    15. {
    16. cout << sizeof(AA) << endl;
    17. system("pause");
    18. return 0;
    19. }


    1. #include
    2. #include
    3. #include
    4. #pragma pack(2)
    5. using namespace std;
    6. struct AA
    7. {
    8. int a; //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    9. char b; //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    10. short c; //长度2>1,按1对齐,偏移量,存放位置区间[5,6]
    11. char d; //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]
    12. //整体存放【0-7】 位置中,共八个字节。
    13. };
    14. struct BB
    15. {
    16. // BB 是注释掉以上 内容 按照2个字节对齐的情况
    17. int a; //长度4>2 按照2对齐,偏移量为0,存放位置区间[0,3]
    18. char b; //长度2>1 按1 对齐,偏移量为4,存放位置区间[4]
    19. short c; //长度2=1,按2对齐,整体偏移到2的倍数6,存放位置区间[6,7]
    20. char d; //长度2>1,按1对齐,偏移量为7,存放位置区间[8],共9个字节。
    21. //整体存放【0-8】 位置中,共9个字节。
    22. };
    23. int main()
    24. {
    25. // cout << sizeof(AA) << endl;
    26. cout << sizeof(BB) << endl;
    27. system("pause");
    28. return 0;
    29. }

      

     

    1. #include
    2. #include
    3. #include
    4. #pragma pack(4)
    5. using namespace std;
    6. struct AA
    7. {
    8. int a; //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    9. char b; //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    10. short c; //长度2>1,按1对齐,偏移量,存放位置区间[5,6]
    11. char d; //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]
    12. //整体存放【0-7】 位置中,共八个字节。
    13. };
    14. struct BB
    15. {
    16. // BB 是注释掉以上 内容 按照2个字节对齐的情况
    17. int a; //长度4>2 按照2对齐,偏移量为0,存放位置区间[0,3]
    18. char b; //长度2>1 按1 对齐,偏移量为4,存放位置区间[4]
    19. short c; //长度2=1,按2对齐,整体偏移到2的倍数6,存放位置区间[6,7]
    20. char d; //长度2>1,按1对齐,偏移量为7,存放位置区间[8],共9个字节。
    21. //整体存放【0-8】 位置中,共9个字节。
    22. };
    23. struct CC
    24. {
    25. int a; //长度4=4 按照4对齐,偏移量为0,存放位置区间[0,3]
    26. char b; //长度4>1 按照1对齐,偏移量为4,存放区间[4]
    27. short c; //长度 2<4 按照两个字节对齐,对齐到2的倍数6 存放位置{6,7}
    28. char d; // 1<4 ,按照1 对齐。偏移量为7.存放位置的区间为[8],总大小为9
    29. };
    30. int main()
    31. {
    32. // cout << sizeof(AA) << endl;
    33. // cout << sizeof(BB) << endl;
    34. cout << sizeof(CC) << endl;
    35. system("pause");
    36. return 0;
    37. }

     

    8字节对齐

    1. #include
    2. #include
    3. #include
    4. #pragma pack(8)
    5. using namespace std;
    6. struct AA
    7. {
    8. int a; //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    9. char b; //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    10. short c; //长度2>1,按1对齐,偏移量,存放位置区间[5,6]
    11. char d; //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]
    12. //整体存放【0-7】 位置中,共八个字节。
    13. };
    14. struct BB
    15. {
    16. // BB 是注释掉以上 内容 按照2个字节对齐的情况
    17. int a; //长度4>2 按照2对齐,偏移量为0,存放位置区间[0,3]
    18. char b; //长度2>1 按1 对齐,偏移量为4,存放位置区间[4]
    19. short c; //长度2=1,按2对齐,整体偏移到2的倍数6,存放位置区间[6,7]
    20. char d; //长度2>1,按1对齐,偏移量为7,存放位置区间[8],共9个字节。
    21. //整体存放【0-8】 位置中,共9个字节。
    22. };
    23. struct CC
    24. {
    25. int a; //长度4=4 按照4对齐,偏移量为0,存放位置区间[0,3]
    26. char b; //长度4>1 按照1对齐,偏移量为4,存放区间[4]
    27. short c; //长度 2<4 按照两个字节对齐,对齐到2的倍数6 存放位置{6,7}
    28. char d; // 1<4 ,按照1 对齐。偏移量为7.存放位置的区间为[8],总大小为9
    29. };
    30. struct DD
    31. {
    32. int a; // 4<8 按4对齐, 偏移:0 位置 {0,3}
    33. char b; // 1<8 按1对齐 偏移:4 位置:{4}
    34. short c; // 2<8 按照2 对齐 偏移 6 位置 {6,7}
    35. char d; // 1<8 按照1 对齐 偏移为7 位置[8] 总大小为9
    36. };
    37. int main()
    38. {
    39. // cout << sizeof(AA) << endl;
    40. // cout << sizeof(BB) << endl;
    41. // cout << sizeof(CC) << endl;
    42. cout << sizeof(DD) << endl;
    43. system("pause");
    44. return 0;
    45. }

    #按照8位,有 包含 double的情况。

    1. #include
    2. #include
    3. #include
    4. #pragma pack(8)
    5. #include
    6. using namespace std;
    7. struct AA
    8. {
    9. int a; //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    10. char b; //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    11. short c; //长度2>1,按1对齐,偏移量,存放位置区间[5,6]
    12. char d; //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]
    13. //整体存放【0-7】 位置中,共八个字节。
    14. };
    15. struct BB
    16. {
    17. // BB 是注释掉以上 内容 按照2个字节对齐的情况
    18. int a; //长度4>2 按照2对齐,偏移量为0,存放位置区间[0,3]
    19. char b; //长度2>1 按1 对齐,偏移量为4,存放位置区间[4]
    20. short c; //长度2=1,按2对齐,整体偏移到2的倍数6,存放位置区间[6,7]
    21. char d; //长度2>1,按1对齐,偏移量为7,存放位置区间[8],共9个字节。
    22. //整体存放【0-8】 位置中,共9个字节。
    23. };
    24. struct CC
    25. {
    26. int a; //长度4=4 按照4对齐,偏移量为0,存放位置区间[0,3]
    27. char b; //长度4>1 按照1对齐,偏移量为4,存放区间[4]
    28. short c; //长度 2<4 按照两个字节对齐,对齐到2的倍数6 存放位置{6,7}
    29. char d; // 1<4 ,按照1 对齐。偏移量为7.存放位置的区间为[8],总大小为9
    30. };
    31. struct DD
    32. {
    33. int a; // 4<8 按4对齐, 偏移:0 位置 {0,3}
    34. char b; // 1<8 按1对齐 偏移:4 位置:{4}
    35. short c; // 2<8 按照2 对齐 偏移 6 位置 {6,7}
    36. char d; // 1<8 按照1 对齐 偏移为7 位置[8] 总大小为9
    37. };
    38. struct EE
    39. {
    40. int a; // 4<8 按4对齐, 偏移:0 位置 {0,3}
    41. double b; // 8==8 按8对齐 偏移量偏移到8的倍数 偏移8 位置:{8,16}
    42. short c; // 2<8 按照2 对齐 偏移 16 位置 {16,17}
    43. char d; // 1<8 按照1 对齐 偏移为17 位置[18] 总大小为9
    44. };
    45. int main()
    46. {
    47. // cout << sizeof(AA) << endl;
    48. // cout << sizeof(BB) << endl;
    49. // cout << sizeof(CC) << endl;
    50. // cout << sizeof(DD) << endl;
    51. cout << sizeof(EE) << endl;
    52. cout << offsetof(EE, b) << endl; //查看偏移了多少内存。
    53. system("pause");
    54. return 0;
    55. }

     例四:结构体包含结构体的运算。

    1. #include
    2. #include
    3. #include
    4. #pragma pack(8)
    5. #include
    6. using namespace std;
    7. struct AA
    8. {
    9. int a; //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    10. char b; //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    11. short c; //长度2>1,按1对齐,偏移量,存放位置区间[5,6]
    12. char d; //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]
    13. //整体存放【0-7】 位置中,共八个字节。
    14. };
    15. struct BB
    16. {
    17. // BB 是注释掉以上 内容 按照2个字节对齐的情况
    18. int a; //长度4>2 按照2对齐,偏移量为0,存放位置区间[0,3]
    19. char b; //长度2>1 按1 对齐,偏移量为4,存放位置区间[4]
    20. short c; //长度2=1,按2对齐,整体偏移到2的倍数6,存放位置区间[6,7]
    21. char d; //长度2>1,按1对齐,偏移量为7,存放位置区间[8],共9个字节。
    22. //整体存放【0-8】 位置中,共9个字节。
    23. };
    24. struct CC
    25. {
    26. int a; //长度4=4 按照4对齐,偏移量为0,存放位置区间[0,3]
    27. char b; //长度4>1 按照1对齐,偏移量为4,存放区间[4]
    28. short c; //长度 2<4 按照两个字节对齐,对齐到2的倍数6 存放位置{6,7}
    29. char d; // 1<4 ,按照1 对齐。偏移量为7.存放位置的区间为[8],总大小为9
    30. };
    31. struct DD
    32. {
    33. int a; // 4<8 按4对齐, 偏移:0 位置 {0,3}
    34. char b; // 1<8 按1对齐 偏移:4 位置:{4}
    35. short c; // 2<8 按照2 对齐 偏移 6 位置 {6,7}
    36. char d; // 1<8 按照1 对齐 偏移为7 位置[8] 总大小为9
    37. };
    38. struct EE
    39. {
    40. int a; // 4<8 按4对齐, 偏移:0 位置 {0,3}
    41. double b; // 8==8 按8对齐 偏移量偏移到8的倍数 偏移8 位置:{8,16}
    42. short c; // 2<8 按照2 对齐 偏移 16 位置 {16,17}
    43. char d; // 1<8 按照1 对齐 偏移为17 位置[18] 总大小为9
    44. };
    45. //=============================================================
    46. struct GG
    47. {
    48. //结构体内部最大元素为int.由于偏移量8刚好是4 的倍数,所以从8 开始存放struct 对应了规则三。
    49. int a1; // 4<8 4 8 [8,11]
    50. char b1; // 1<8 1 12 [12]
    51. short c1; // 2<8 2 14 [14,15]
    52. char d1; // 1 <8 1 16 [16]
    53. };
    54. struct FF
    55. {
    56. int a; // 4<8 按4 偏移0 存放的位置【0,3】
    57. char b; // 1<8 按1 偏移4 [4]
    58. short c; // 2<8 2 6 [6,7]
    59. GG g;
    60. //子strcut整体对齐系数=min((max(int,short,char),8))=4. 将内存补齐到4 的整数倍 20.
    61. char d; // 1<8 1 21 21
    62. //整体对齐系数 4 所有有21 补到24.
    63. };
    64. //===========================================
    65. int main()
    66. {
    67. // cout << sizeof(AA) << endl;
    68. // cout << sizeof(BB) << endl;
    69. // cout << sizeof(CC) << endl;
    70. // cout << sizeof(DD) << endl;
    71. // cout << sizeof(EE) << endl;
    72. // cout << offsetof(EE, b) << endl; //查看偏移了多少内存。
    73. cout << sizeof(FF) << endl;
    74. // cout << offsetof(FF, GG) << endl;
    75. system("pause");
    76. return 0;
    77. }

     

     

     4.练习:

            

    1. #include
    2. #include
    3. #include
    4. #pragma pack(8)
    5. using namespace std;
    6. struct A
    7. {
    8. int a; // [0,4]
    9. double b;
    10. // [ 8, 16 ]
    11. float c;
    12. // [ 17, 20 ]
    13. };
    14. // #24
    15. struct B
    16. {
    17. char e[2]; // 1<8 按照2对齐 偏移 0 位置【0,1】
    18. short h; // 2<8 2 2 [2,4]
    19. A a; // 24
    20. // 一共28 偏移一起达到32.
    21. };
    22. int main()
    23. {
    24. cout << sizeof(B) << endl;
    25. system("pause");
    26. return 0;
    27. }

     

     

  • 相关阅读:
    流式计算和实时计算有什么区别?
    【C++学习】智能指针
    SpringBoot集成security
    docker阅读笔记
    【OceanBase】四种不同的数据迁移方式
    Kafka 在分布式系统中的 7 大应用场景
    EF Core 配置模型
    2022 最全 Java 面试手册终于开源了,包含了 29 个知识点
    多目标应用:多目标蜣螂优化算法求解多旅行商问题(Multiple Traveling Salesman Problem, MTSP)
    Tlsr8258开发-修改蓝牙hid mouse
  • 原文地址:https://blog.csdn.net/cat_fish_rain/article/details/133279567