一:内存对齐原则
以下是内存对齐的规则,以及各种数据类型所占用的字节
1:数据成员对齐规则:数据成员的第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员子成员大小的整数倍开始存储
2:结构体作为成员:如果一个结构里有某些结构体成员,那么结构体成员要从其内部最大元素大小的整数倍地址开始存储,比如struct a中存有struct b,b中有char,int,double等元素,那么b应该从最大的元素(doule 8字节)的整数倍开始存储
3:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足要补齐
下图为各种数据类型所占的字节大小
了解以上原则后,我们开始根据这个规则计算下边几个结构体内存大小
从上图可以看到,为什么struct1 与 struct2 中的变量一致,却得出来两个不同的结果呢? 这就要参考内存对齐规则来分析一下了
-
struct1中:a为double类型,占用8个字节,所以存储地址为0-7,b为char类型,占用1个字节,占用地址为8,c为int类型,占用4个字节。依据以后每个数据成员存储的起始位置要从该成员大小或者成员子成员大小的整数倍开始存储这个规则,9,10,11号位置并不是4的倍数。因此只能存在12,13,14,15号位置,d为short类型,占用2个字节,存在16,17号位。根据第三条规则:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足要补齐 ,我们得到的17并不满足这条规则,因此按照此规则,最后结果为 8(double占位8字节,为最大的成员) * 3 = 24字节。
-
struct2中,a为double类型,存储在0-7,b为int类型,存储在8-11,c为char类型,存储在12,d为short类型,存储在14-15. 最后根据第三条规则,得到结果为16字节
-
由以上分析可知:成员变量的顺序不同,最后所占用的内存空间竟然不同,所以我们在定义一些属性的时候,可以按照最合理的方式排列,以此节约内存空间。
struct LGStruct3 {
double a; //8 [0 7]
int b; //4 [8 11]
char c; //1 [12]
short d; //2 13 [14 15]
//根据第一条规则,第一个之后的成员变量,内存要根据该成员大小或者子成员大小的整数倍开始存储,
//所以,13不是2的整数倍,要从14开始存储
int e; //4 [16 17 18 19]
struct LGStruct1 str; //24 [24 + 24] 8
//这里为什么从24开始存呢? 根据第二条规则可知,如果结构中有结构体成员,
//要从最大元素整数倍开始存储,24为8的倍数。
//根据上图所知struct1大小为24,因此24+24 = 48,
//根据第三条规则,结构体的总大小,需要是内部最大成员整数倍 ,LGStruct3中最大字节为8 ,48是8的整数倍,满足第三条规则
}struct3;
、、、
输出一下看看结果是否正确
、、、
NSLog(@"struct1:%lu-struct2:%lu-struct3:%lu",sizeof(struct1),sizeof(struct2),sizeof(struct3));
、、、
这里要补充一下sizeof的知识
- 1:sizeof是一个操作符,不是函数
- 2:sizeof() 传入的主要对象是数据类型,在编译阶段就会返回该对象占用空间的大小