內(nèi)存對(duì)齊原則
-
數(shù)據(jù)成員對(duì)?規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員存儲(chǔ)的起始位置要從該成員大小或者成員的子成員大小(只要該成員有子成員,比如說(shuō)是數(shù)組,結(jié)構(gòu)體等)的整數(shù)倍開(kāi)始(比如int為4字節(jié),則要從4的整數(shù)倍地址開(kāi)始存儲(chǔ))。 -
結(jié)構(gòu)體作為成員:如果一個(gè)結(jié)構(gòu)里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小的整數(shù)倍地址開(kāi)始存儲(chǔ)(struct a里存有struct b,b里有char、int 、double等元素,那b應(yīng)該從8的整數(shù)倍開(kāi)始存儲(chǔ))。 -
結(jié)構(gòu)體的總大小,也就是sizeof的結(jié)果,必須是其內(nèi)部最大成員的整數(shù)倍,不足的要補(bǔ)?。

驗(yàn)證對(duì)齊規(guī)則
結(jié)構(gòu)體嵌套成員變量
我們通過(guò)定義兩個(gè)結(jié)構(gòu)體,分別計(jì)算他們的內(nèi)存大小
//1、定義兩個(gè)結(jié)構(gòu)體
struct Mystruct1{
char a; //1字節(jié)
double b; //8字節(jié)
int c; //4字節(jié)
short d; //2字節(jié)
}Mystruct1;
struct Mystruct2{
double b; //8字節(jié)
int c; //4字節(jié)
short d; //2字節(jié)
char a; //1字節(jié)
}Mystruct2;
//計(jì)算 結(jié)構(gòu)體占用的內(nèi)存大小
NSLog(@"%lu-%lu",sizeof(Mystruct1),sizeof(Mystruct2));
輸出結(jié)果如下所示:

我們可以通過(guò)下圖圖來(lái)說(shuō)明下為什么兩個(gè)結(jié)構(gòu)體MyStruct1 & MyStruct2的內(nèi)存大小打印不一致的情況,如圖所示

計(jì)算結(jié)構(gòu)體MyStruct1的大小
-
變量a:占1個(gè)字節(jié),為第一個(gè)成員變量,因此從0開(kāi)始,此時(shí)min(0,1),即0位置存儲(chǔ)a。 -
變量b:占8個(gè)字節(jié),從1開(kāi)始計(jì)算,此時(shí)min(1,8),因?yàn)?/8=0不是整數(shù)倍,所以要先偏移到(8,8),即8-15位置存儲(chǔ)b。 -
變量c:占4個(gè)字節(jié),從16開(kāi)始計(jì)算,此時(shí)min(16,4),因?yàn)?6/4=4是整數(shù)倍,所以無(wú)需偏移,即16-19位置存儲(chǔ)c。 -
變量d:占2個(gè)字節(jié),從20開(kāi)始計(jì)算,此時(shí)min(20,2),因?yàn)?0/2=10是整數(shù)倍,所以無(wú)需偏移,即20-21位置存儲(chǔ)d。
此時(shí)MyStruct1的實(shí)際所需內(nèi)存大小為22個(gè)字節(jié),但因?yàn)?code>結(jié)構(gòu)體的總大小必須是其內(nèi)部最大成員的整數(shù)倍,且MyStruct1中最大成員變量為b占8字節(jié),所以MyStruct1的內(nèi)存大小只能向上取整為8*3=24字節(jié)。
計(jì)算結(jié)構(gòu)體MyStruct2的大小
-
變量b:占8個(gè)字節(jié),為第一個(gè)成員變量,因此從0開(kāi)始,此時(shí)min(0,8),即0-7位置存儲(chǔ)b。 -
變量c:占4個(gè)字節(jié),從8開(kāi)始計(jì)算,此時(shí)min(8,4),因?yàn)?/8=2是整數(shù)倍,所以無(wú)需偏移,即8-11位置存儲(chǔ)c。 -
變量d:占2個(gè)字節(jié),從12開(kāi)始計(jì)算,此時(shí)min(12,2),因?yàn)?2/2=6是整數(shù)倍,所以無(wú)需偏移,即12-13位置存儲(chǔ)d。 -
變量a:占1個(gè)字節(jié),從14開(kāi)始計(jì)算,此時(shí)min(14,1),因?yàn)?4/1=14是整數(shù)倍,所以無(wú)需偏移,即14位置存儲(chǔ)a。
此時(shí)MyStruct2的實(shí)際所需內(nèi)存大小為15個(gè)字節(jié),但因?yàn)?code>結(jié)構(gòu)體的總大小必須是其內(nèi)部最大成員的整數(shù)倍,且MyStruct2中最大成員變量為b占8字節(jié),所以MyStruct2的內(nèi)存大小只能向上取整為8*2=16字節(jié)。
結(jié)構(gòu)體嵌套結(jié)構(gòu)體
首先定義一個(gè)結(jié)構(gòu)體MyStruct3,在MyStruct3中嵌套MyStruct2,如下所示
//1、結(jié)構(gòu)體嵌套結(jié)構(gòu)體
struct Mystruct3{
double b; //8字節(jié)
int c; //4字節(jié)
short d; //2字節(jié)
char a; //1字節(jié)
struct Mystruct2 str;
}Mystruct3;
//2、打印 Mystruct3 的內(nèi)存大小
NSLog(@"Mystruct3內(nèi)存大小:%lu", sizeof(Mystruct3));
NSLog(@"Mystruct3中結(jié)構(gòu)體成員內(nèi)存大?。?lu", sizeof(Mystruct3.str));
輸出結(jié)果如下所示:

計(jì)算結(jié)構(gòu)體MyStruct3的大小
-
變量b:占8個(gè)字節(jié),為第一個(gè)成員變量,因此從0開(kāi)始,此時(shí)min(0,8),即0-7位置存儲(chǔ)b。 -
變量c:占4個(gè)字節(jié),從8開(kāi)始計(jì)算,此時(shí)min(8,4),因?yàn)?/8=2是整數(shù)倍,所以無(wú)需偏移,即8-11位置存儲(chǔ)c。 -
變量d:占2個(gè)字節(jié),從12開(kāi)始計(jì)算,此時(shí)min(12,2),因?yàn)?2/2=6是整數(shù)倍,所以無(wú)需偏移,即12-13位置存儲(chǔ)d。 -
變量a:占1個(gè)字節(jié),從14開(kāi)始計(jì)算,此時(shí)min(14,1),因?yàn)?4/1=14是整數(shù)倍,所以無(wú)需偏移,即14位置存儲(chǔ)a。 -
結(jié)構(gòu)體成員str:str是一個(gè)結(jié)構(gòu)體,根據(jù)內(nèi)存對(duì)齊原則二,結(jié)構(gòu)體成員要從其內(nèi)部最大成員大小的整數(shù)倍開(kāi)始存儲(chǔ),而MyStruct2中最大的成員大小為8,所以str要從8的整數(shù)倍開(kāi)始,當(dāng)前是從15開(kāi)始,但不符合要求,需要往后移動(dòng)到16,16是8的整數(shù)倍,符合內(nèi)存對(duì)齊原則,即 16-31位置存儲(chǔ) str。
此時(shí)MyStruct3的實(shí)際所需內(nèi)存大小為 32字節(jié),而MyStruct3中最大變量為str,其最大成員內(nèi)存字節(jié)數(shù)為8,所以 MyStruc3 實(shí)際的內(nèi)存大小必須是 8 的整數(shù)倍,32正好是8的整數(shù)倍,所以sizeof(MyStruct3) 的結(jié)果是 32。
其內(nèi)存存儲(chǔ)情況如下所示:
