結(jié)構(gòu)體內(nèi)存對(duì)齊

想要計(jì)算結(jié)構(gòu)體大小,必須先掌握結(jié)構(gòu)體內(nèi)存對(duì)齊規(guī)則:

1.第一個(gè)成員在與結(jié)構(gòu)體變量偏移量為0的地址處。

2.其他成員變量要對(duì)齊到某個(gè)數(shù)字(對(duì)齊數(shù))的整數(shù)倍的地址處。

3.對(duì)齊數(shù) = 編譯器默認(rèn)的一個(gè)對(duì)齊數(shù) 與 該成員大小的較小值。 windows(32)/VC6.0 中默認(rèn)的值為8, linux(32)/GCC 中的默認(rèn)值為4。

4.結(jié)構(gòu)體總大小為最大對(duì)齊數(shù)(每個(gè)成員變量都有一個(gè)對(duì)齊數(shù))的整數(shù)倍。

如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍。


練習(xí)1

struct S1{

char c1;

int i;

char c2;

};


練習(xí)1

c1先存入0地址處,i的對(duì)齊數(shù)為4(int 為4, 默認(rèn)為8,取?。谧兞科茷?的地址處存入(即4處)(這里為什么是4呢?這個(gè)是根據(jù)我們的第二條規(guī)則,從地址為0開始,對(duì)齊數(shù)的整數(shù)倍開始填入),c2對(duì)齊數(shù)為1,在8處存入,共消耗9個(gè)地址;結(jié)構(gòu)體總大小為最大對(duì)齊數(shù)(4)的整數(shù)倍,即12。

練習(xí)2

struct S2

{

char c1;

char c2;

int i;

};


練習(xí)2

c1存入0地址處,c2對(duì)齊數(shù)為1(char為1,默認(rèn)8,取小),在變量偏移為0的地址處存入(即1處),i的對(duì)齊數(shù)為4(int為4,默認(rèn)8,取?。谧兞科茷?的地址處存入(即4處),共消耗8個(gè)地址;結(jié)構(gòu)體總大小為最大對(duì)齊數(shù)(4)的整數(shù)倍,即8。

練習(xí)3

struct S3

{

double d;

char c;

int i;

};


練習(xí)3

d存入0地址處,c對(duì)齊數(shù)為1,存入8處,i對(duì)齊數(shù)為4,存入12處,共消耗16地址;結(jié)構(gòu)體總大小為最大對(duì)齊數(shù)(4)的整數(shù)倍,即16。

練習(xí)4-結(jié)構(gòu)體嵌套問題

struct S4

{

char c1;

struct S3 s3;

double d;

};


練習(xí)4

c1存入0地址處,S3對(duì)齊到其最大對(duì)齊數(shù)的整數(shù)倍處(即8處),依次對(duì)齊d、c、i、d,消耗32個(gè)地址,結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(即8)的整數(shù)倍,32恰好是8的整數(shù)倍,所以為32。


2. 為什么存在內(nèi)存對(duì)齊

大部分的參考資料是這樣說的:

平臺(tái)原因(移植原因): 不是所有的硬件平臺(tái)都能訪問任意地址上的任意數(shù)據(jù)的;某些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。

性能原因: 數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對(duì)齊。 原因在于,為了訪問未對(duì)齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問;而對(duì)齊的內(nèi)存訪問僅需要一次訪問。

總體來說:

結(jié)構(gòu)體的內(nèi)存對(duì)齊是拿空間來換取時(shí)間的做法

那在設(shè)計(jì)結(jié)構(gòu)體的時(shí)候,我們既要滿足對(duì)齊,又要節(jié)省空間,如何做到:

讓占用空間小的成員盡量集中在一起。

//例如:

struct S1

{

char c1;

int i;

char c2;

};

struct S2

{

char c1;

char c2;

int i;

};

S1和S2類型的成員一模一樣,但是S1和S2所占空間的大小有了一些區(qū)別。

3. 修改默認(rèn)對(duì)齊數(shù)

#include <stdio.h>

#pragma pack(8)//設(shè)置默認(rèn)對(duì)齊數(shù)為8

struct S1

{

char c1;

int i;

char c2;

};

#pragma pack()//取消設(shè)置的默認(rèn)對(duì)齊數(shù),還原為默認(rèn)

#pragma pack(1)//設(shè)置默認(rèn)對(duì)齊數(shù)為

struct S2

{

char c1;

int i;

char c2;

};

#pragma pack()//取消設(shè)置的默認(rèn)對(duì)齊數(shù),還原為默認(rèn)

int main()

{

//輸出的結(jié)果是什么?

printf("%d\n", sizeof(struct S1));? ? ? ? ? //12

printf("%d\n", sizeof(struct S2));? ? ? ? ? //6

return 0;

}

結(jié)論:

結(jié)構(gòu)在對(duì)齊方式不合適的時(shí)候,那么可以自己更改默認(rèn)對(duì)齊數(shù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容