内存对齐规则:
- 数据成员对齐规则
结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset(偏移)为0的地方,以后每个数据成员的对齐按照 #pragma pack 指定的数值和这个数据成员自身长度中,比较小的那个进行 - 结构(或联合)的整体对齐规则
在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照 #pragma pack 指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。 - 结构体作为成员:
如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。
#pragma pack(n) 对齐系数:
每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。其中,Xcode 中默认为#pragma pack(8)
系统对齐:
- 在操作系统中对结构(struct)(或联合(union))的数据成员分配的内存是操作系统的对齐系数的倍数。例如IOS中的系统对齐系数是16。
演练:
1.
struct StructOne {
长度 对齐 偏移 区间
char a; 1 < 8 1 0 [0]
double b; 8 = 8 8 8 [8, 15]
int c; 4 < 8 4 16 [16, 19]
short d; 2 < 8 2 20 [20, 21]
} MyStruct1;
解读:
1、每个数据成员的对齐按照 #pragma pack 指定的数值和这个数据成员自身长度中,比较小的那个进行
-- char a 的自身长度为 1, 1 < 8, 按 1 对齐
-- double b 的自身长度为 8, 8 = 8, 按 8 对齐
-- int c 的自身长度为 4, 4 < 8, 按 4 对齐
-- short d 的自身长度为 2, 2 < 8, 按 2 对齐
2、第一个数据成员放在offset为0的地方
-- char a 的偏移为 1
-- double b 的偏移为 8
-- int c 的偏移为 4
-- short d 的偏移为 2
3、整体将按照 #pragma pack 指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
min((max(int,short,char,double), 8) = 8,将 21 提升到 8 的倍数,则为 24,所以最终结果为 24 个字节
2.
struct StructOne {
长度 对齐 偏移 区间
double b; 8 = 8 8 0 [0, 7]
char a; 1 < 8 1 8 [8]
short d; 2 < 8 2 10 [10, 11]
int c; 4 < 8 4 12 [12, 15]
} MyStruct1;
解读:
这个和演练1不同的是short d,由于它是 2 对齐,上一个偏移量为 9,
9不是2的整数倍,所以向上取整,到10,"short b" 偏移为10
整体对齐系数 = min((max(int,short,char,double), 8) = 8,将15提升到8的倍数,则为16,所以最终结果为16个字节
3. 结构体包含结构体:
struct EE
{ 长度 对齐 偏移 区间
int a; 4 < 8 4 0 [0, 3]
char b; 1 < 8 1 4 [4]
short c; 2 < 8 2 6 [6, 7]
struct FF //结构体内部最大元素为int ,由于偏移量为8刚好是4的整数倍,所以从8开始存放接下来的struct FF
{
int a1; 4 < 8 4 8 [8, 11]
char b1; 1 < 8 1 12 [12]
short c1; 2 < 8 2 14 [14, 15]
char d1; 1 < 8 1 16 [16]
};// 内部结构体整体对齐:min(max(int, char, short), 8) = 4, 将内存大小由17补齐到4的整数倍20
char d; 1 < 8 1 21 [21]
// 整体对齐系数 = min((max(int,short,char), 8) = 4,将内存大小由21补齐到4的整数倍24
};
struct B { 长度 对齐 偏移 区间
char e[2]; 1 < 8 2 0 [0, 1]
short h; 2 < 8 2 2 [2, 3]
struct A { //结构体内部最大元素为double ,由于偏移量为8刚好是4的整数倍,所以从8开始存放接下来的struct A
int a; 4 < 8 4 8 [8, 11]
double b; 8 = 8 8 16 [16, 23]
float c; 4 < 8 4 24 [24, 27]
};
// 整体对齐系数 = min((max(int,double ,float), 8) = 8
// 将内存大小由28补齐到8的整数倍32,∴ result = 32
};
练习
1.
struct x_ {
char a; // 1 byte
int b; // 4 bytes
short c; // 2 bytes
char d; // 1 byte
} MyStruct1;
struct y_ {
int b; // 4 bytes
char a; // 1 byte
char d; // 1 byte
short c; // 2 bytes
} MyStruct2;
NSLog(@"%lu---%lu--", sizeof(MyStruct1), sizeof(MyStruct2));
//12---8--
2.
struct StructOne {
char a; // 1字节
double b; // 8字节
int c; // 4字节
short d; // 2字节
} MyStruct1;
struct StructTwo {
double b; // 8字节
char a; // 1字节
short d; // 2字节
int c; // 4字节
} MyStruct2;
NSLog(@"%lu---%lu--", sizeof(MyStruct1), sizeof(MyStruct2));
//24---16--
3.
struct DD
{
double a;
char b;
short c;
struct FF
{
int a1;
char b1;
short c1;
char d1;
};
char d;
}Test;
NSLog(@"%lu", sizeof(Test));
//24
4.
struct B {
char d;
double h;
struct A {
int a;
double b;
float c;
};
} Test;
NSLog(@"%lu", sizeof(Test));
//40