这里我们来分析结构体内存对齐方式, 从中我们可以间接的分析出在OC中内存的对齐方式大概什么样.
进行分析前我们要先知道不同类型的属性, 所对应的内存空间是什么. 如下:
C | OC | 32位 | 64位 |
bool | BOOL(64位) | 1 | 1 |
signed char | (__signed char)int8_t BOOL(32位) | 1 | 1 |
unsigned char | Boolean | 1 | 1 |
short | int16_t | 2 | 2 |
unsigned short | unichar | 2 | 2 |
int int32_t | NSInteger(32位) boolean_t(32位) | 4 | 4 |
unsigned int | boolean_t(64位) NSInteger(32位) | 4 | 4 |
long | NSInteger(64位) | 4 | 8 |
unsigned long | NSInteger(64位) | 4 | 8 |
long long | int64_t | 8 | 8 |
float | CGFloat(32位) | 4 | 4 |
double | CGFloat(64位) | 8 | 8 |
内存对齐的原则
- 数据成员对齐规则: 结构(struct)(或联合(union))的数据成员, 第一个数据成员放在offset为0的地方, 以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员, 比如说是数组, 结构体等)的整数倍开始(比如int为4字节, 则要从4的整数倍地址开始存储).
- 结构体作为成员: 如果一个结构里有某些结构体成员, 则结构体成员要从其内部最大元素大小的整数倍地址开始存储. (struct a里存有struct b, b里有char, int, double等元素, 那b应该从8的整数倍开始存储.)
- 收尾工作: 结构体的总大小, 也就是sizeof的结果, 必须是其内部最大成员的整数倍, 不足的要补齐.
例子
struct LGStruct1 { double a; // 8 (0-7) char b; // 1 [8 1] (8) int c; // 4 [9 4] 9 10 11 (12 13 14 15) short d; // 2 [16 2] (16 17) }struct1; // 内部需要的大小为: 17 // 最大属性 : 8 // 结构体整数倍: 24 struct LGStruct2 { double a; //8 (0-7) int b; //4 (8 9 10 11) char c; //1 (12) short d; //2 13 (14 15) - 16 }struct2; // 内部需要的大小为: 16 // 最大属性 : 8 // 结构体整数倍: 16
扩展结构体中有其他结构体
接上面代码分析:
struct LGStruct2 { double a; //8 (0-7) int b; //4 (8 9 10 11) char c; //1 (12) short d; //2 13 (14 15) - 16 struct LGStruct1 e; // 这个需要17在例子1中以及分析很清晰了, 16 + 17 从17 ~ 33 }struct2; // 内部需要的大小为: 33 // 最大属性 : 8 // 结构体整数倍: 40 struct LGStruct2 { double a; //8 (0-7) int b; //4 (8 9 10 11) struct LGStruct1 e; //16 + 17 = 34 从8的整数倍16开始 char c; //1 (40) 从40开始 short d; //2 41 42 - 42 }struct2; // 内部需要的大小为: 42 // 最大属性 : 8 // 结构体整数倍: 48