iOS 底层探索02——结构体对齐原则

837 阅读3分钟

这是我参与更文挑战的第3天,活动详情查看: 更文挑战

结构体内存对齐规则

规则1. 数据成员对⻬规则:

结构(struct)(或联合(union))的数据成员,第 ⼀个数据成员放在offset为0的地⽅,以后每个数据成员存储的起始位置要 从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组, 结构体等)的整数倍开始(⽐如int为4字节,则要从4的整数倍地址开始存 储。

规则2. 结构体作为成员:

如果⼀个结构体⾥有某些结构体成员,则结构体成员要从 其内部最⼤元素⼤⼩的整数倍地址开始存储.(struct a⾥存有struct b,b ⾥有char,int ,double等元素,那b应该从8的整数倍开始存储.)

规则3. 收尾⼯作:

结构体的总⼤⼩,也就是sizeof的结果,.必须是其内部最⼤成员的整数倍.不⾜的要补⻬。

示例

我们用占用大小表示当前类型的数据占用的空间大小,用存储位置表示占用的存储地址,其中() 表示因为某些对齐规则需要“牺牲“掉的空间,[]表示数据实际存储的空间;

  1. 示例1
struct GCStruct1 {  占用大小    存储位置
    double a;       // 8      [0-7]
    char b;         // 1      [8]
    int c;          // 4      (9-11)[12-15]
    short d;        // 2      [16-17]
}struct1;
  • GCStruct1 的成员变量只占用了15个字节;
  • 因为规则1,(9-11)的位置需要对齐而空出来,实际上需要的空间有[0-17]这18个字节;
  • 因为规则3,必须是最大成员double型8的倍数;
  • GCStruct1实际占用24个字节;
  1. 示例2
struct GCStruct2 {  占用大小    存储位置
    double a;      //8        [0-7] 
    int b;         //4        [8-11]
    char c;        //1        [12]
    short d;       //2        (13)[14-15]
}struct2;
  • GCStruct2 的成员变量只占用了15个字节,
  • 因为规则1,(13)的位置需要对齐而空出来,实际上需要的空间有[0-15]这16个字节;
  • 因为规则3,必须是最大成员double型8的倍数,16符合条件;
  • GCStruct2实际占用16个字节;
  1. 示例3
struct GCStruct3 {         占用大小    存储位置
    double a;              //8        [0-7]
    int b;                 //4        [8-11]
    char c;                //1        [12]
    short d;               //2        (13)[14-15]
    int e;                 //4        [16-19]
    struct GCStruct1 str;  //24       (20-23)[24-41]
}struct3;
  • GCStruct3 的成员变量只占用了8+4+1+2+4+24=43个字节
  • 因为规则1,(13)的位置需要对齐而空出来
  • 因为规则2,成员变量str存储时需要从GCStruct1内部最大的成员变量double型 8的倍数开始存储,所以(20-23)的位置需要对齐而空出来,str需要的实际空间是18个字节(不使用规则3对齐),存储的位置是[24-41]这18个字节,此时struct3一共占用[0-41]共42个字节;
  • 因为规则3,必须是最大成员double类型8的倍数,则最终GCStruct3实际占用48个字节;

代码验证

11.jpg 最终代码执行结果与研究一致;

结构体规则补充

  1. 当结构体作为成员变量被嵌套进其他结构体时,其size为只受规则2限制,不受规则3限制,不需要处理为最大的整数倍,而是等加到外部之后统一处理;
  2. 当结构体作为成员变量被嵌套进其他结构体时,被嵌套的结构体不可以作为外层结构体的最大成员来计算最终size,需要拆分后将其成员变量与外层放到一起后找出最大成员的size进行整数倍对齐;