结构体内存对齐分析

内存对齐

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#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的倍数

运行得出结果

运行结果

总结

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

你可能感兴趣的:(结构体内存对齐分析)