C語言詳解結(jié)構(gòu)體的內(nèi)存對齊與大小計算
結(jié)構(gòu)體的內(nèi)存對齊
1、計算結(jié)構(gòu)體的大小
struct S1 { char c1; // 1 byte,默認(rèn)對齊數(shù)為8,所以c1的對齊數(shù)是1,第一個成員變量放在與結(jié)構(gòu)體變量偏移量為0的地址處 int i; // 4 byte,默認(rèn)對齊數(shù)為8,所以i的對齊數(shù)是4,所以i要放到偏移量為 4的整數(shù)倍 的地址處 char c2; // 1 byte,默認(rèn)對齊數(shù)為8,所以c2的對齊數(shù)是1,所以c2要放到偏移量為 1的整數(shù)倍 的地址處 //最大對齊數(shù)是4 //成員大小為9,不是最大對齊數(shù)4的整數(shù)倍,所以結(jié)構(gòu)體總大小為12 }; printf("%d\n", sizeof(struct S1));
原理分析:
【練習(xí)題】
// 練習(xí)1 struct S2 { char c1; // 1 byte / 8,對齊數(shù)是1, char c2; // 1 byte / 8,對齊數(shù)是1, int i; // 4 byte / 8,對齊數(shù)是4, // 最大對齊數(shù)是4 // 成員大小為8,是最大對齊數(shù)的整數(shù)倍,所以結(jié)構(gòu)體總大小為8 }; printf("%d\n", sizeof(struct S2)); // 練習(xí)2 struct S3 { char c; // 1/8,對齊數(shù)是1 int i; // 4/8,對齊數(shù)是4 double d; // 8/8,對齊數(shù)是8 // 最大對齊數(shù)是8 // 成員大小為16,是最大對齊數(shù)的整數(shù)倍,所以結(jié)構(gòu)體總大小為16 }; printf("%d\n", sizeof(struct S3)); // 練習(xí)3-結(jié)構(gòu)體嵌套問題 struct S4 { char c1; // 1/8,對齊數(shù)是1 struct S3 s3; // 16 byte,【S3的最大對齊數(shù)是8】,所以s3要放到8的整數(shù)倍的地址處 double d; // 8/8,對齊數(shù)是8 // 最大對齊數(shù)是8 // 成員大小為32,是最大對齊數(shù)的整數(shù)倍,所以結(jié)構(gòu)體總大小為32 }; printf("%d\n", sizeof(struct S4));
2、結(jié)構(gòu)體的對齊規(guī)則
第一個成員變量在與結(jié)構(gòu)體變量偏移量為 0 的地址處。
其他成員變量要對齊到某個數(shù)字(對齊數(shù))的整數(shù)倍的地址處。
- 對齊數(shù) =「編譯器默認(rèn)的一個對齊數(shù)」與「該成員大小」中的較小值。
- VS中默認(rèn)對齊數(shù)為「8」,Linux中沒有對齊數(shù)
結(jié)構(gòu)體總大小為:最大對齊數(shù)(每個成員變量都有一個對齊數(shù))的整數(shù)倍。
如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對齊到自己的最大對齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對齊數(shù)(含嵌套結(jié)構(gòu)體的對齊數(shù))的整數(shù)倍。
3、為什么存在內(nèi)存對齊?
大部分的參考資料是這樣說的:
- 平臺原因(移植原因): 不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù)的;某些硬件平臺只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。(那我們就要將數(shù)據(jù)對齊到能夠訪問的這些地址處)
- 性能原因:數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對齊。 原因在于,為了訪問未對齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問;而對齊的內(nèi)存訪問僅需要一次訪問。
4、總結(jié)
結(jié)構(gòu)體的內(nèi)存對齊是拿空間來換取時間的做法。
思考:那在設(shè)計結(jié)構(gòu)體的時候,我們既要滿足對齊,又要節(jié)省空間,如何做到:
讓占用空間小的成員盡量集中在一起。
// 例如: struct S1 { char c1; // 1/8,對齊數(shù)是1 int i; // 4/8,對齊數(shù)是4 char c2; // 1/8,對齊數(shù)是1 // 最大對齊數(shù)是4 // 成員大小為9,不是最大對齊數(shù)的整數(shù)倍,所以結(jié)構(gòu)體總大小為12 }; struct S2 { char c1; // 1/8,對齊數(shù)是1 char c2; // 1/8,對齊數(shù)是1 int i; // 4/8,對齊數(shù)是4 // 最大對齊數(shù)是4 // 成員大小為8,是最大對齊數(shù)的整數(shù)倍,所以結(jié)構(gòu)體總大小為8 };
S1和S2類型的成員一模一樣,但是S1和S2所占空間的大小卻有了一些區(qū)別。
到此這篇關(guān)于C語言詳解結(jié)構(gòu)體的內(nèi)存對齊與大小計算的文章就介紹到這了,更多相關(guān)C語言結(jié)構(gòu)體內(nèi)存對齊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解C++循環(huán)創(chuàng)建多級目錄及判斷目錄是否存在的方法
這篇文章主要介紹了C++循環(huán)創(chuàng)建多級目錄及判斷目錄是否存在的方法,文中代碼有一個針對各種系統(tǒng)進(jìn)行判斷來加載不同頭文件的方法,需要的朋友可以參考下2016-03-03