美文网首页
结构体内存对齐分析

结构体内存对齐分析

作者: 冼同学 | 来源:发表于2021-06-09 17:27 被阅读0次

    内存对齐

    每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。宏命令#pragma pack会告诉编译器如何进行内存对齐。XCODE中默认为#pragma pack(8)。其接受的参数为:'1', '2', '4', '8', or '16'。

    内存对齐的规则

    • 数据成员对齐规则:struct 或 union (以下统称结构体)的数据成员,第一个数据成员A放在偏移为 0 的地方,以后每个数据成员B的偏移为(#pragma pack(指定的数n) 与 该数据成员(也就是 B)的自身长度中较小那个数的整数倍,不够整数倍的补齐。
    • 数据成员为结构体:如果结构体的数据成员还为结构体,则该数据成员的“自身长度”为其内部最大元素的大小。struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
    • 结构体的整体对齐规则:在数据成员按照上述第一步完成各自对齐之后,结构体本身也要进行对齐。对齐会将结构体的大小调整为(#pragma pack(指定的数n) 与 结构体中的最大长度的数据成员中较小那个的整数倍,不够的补齐。
      补充:Xcode 中默认为#pragma pack(8)。如果在代码执行前加一句#pragma pack(1) 时就代表不进行内存对齐!

    内存对齐的好处

    1. 为了兼容,方便移植。CPU是一块块的进行进行内存访问。有一些硬件平台不允许随机访问,只能访问对齐后的内存地址,否则会报异常
    2. 为了提高CPU内存访问速度。CPU访问非对齐的内存时需要进行多次拼接。如下图,比如需要读取从[2, 5]的内存,需要分别读取两次,然后还需要做位移的运算,最后才能得到需要的数据。这中间的损耗就会影响访问速度。


      CPU访问非对齐

    案例分析

    开发常见的数据类型占位大小

    类型占位大小
    结合以上所概述的内容分析以下三个结构体的内存
    struct Struct1{
        double a; //0-7
        char b;   //8
        int c;    //起始min(8,4)=4,所以从4的倍数开始 12 13 14 15
        short d;  //16 17
    } structOne;  //min(8,8)=8, 8的倍数 24;  
    
    struct Struct2{
        double a; //0-7
        int c;    //起始min(8,4)=4,所以从4的倍数开始 8 9 10 11
        char b;   //12
        short d;  //14 15
    } structTwo;  //min(8,8)=8, 8的倍数  16
    
    struct Struct3{
        double a; //0-7
        int c;    //起始min(8,4)=4,所以从4的倍数开始 8 9 10 11
        char b;   //12
        short d;  //14 15
        int e;     //16 17 18 19
        struct  Struct1  stu_xjl; //Struct1成员里面最大的是占8位,所以开始位置必须为8的倍数,也就是24
    } structThree;  //结果:24 + Stuct1的大小:24  = 48,48刚好是8的倍数
    

    运行得出结果

    运行结果

    总结

    本文主要讲述了内存对齐的三个原则以及其存在的必要性,最后还分析了结构体在内存对齐下的内存大小(不同的变量顺序会导致结构体大小不一样哦)

    相关文章

      网友评论

          本文标题:结构体内存对齐分析

          本文链接:https://www.haomeiwen.com/subject/azbseltx.html