內(nèi)存對(duì)齊的原因:
1.平臺(tái)原因
不是所有硬件平臺(tái)都可以訪問(wèn)任意地址上的任意數(shù)據(jù);
某些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。
2.性能原因
數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能的在自然邊界上對(duì)齊。
原因在于在訪問(wèn)未對(duì)齊的內(nèi)存時(shí),處理器需要進(jìn)行兩次內(nèi)存訪問(wèn);而對(duì)齊的內(nèi)存訪問(wèn)僅需要一次。
結(jié)構(gòu)體(struct)內(nèi)存對(duì)齊規(guī)則:
1.第一個(gè)成員在與結(jié)構(gòu)體變量偏移量為0的地址處。
2.其它成員變量要對(duì)齊到某個(gè)數(shù)字(對(duì)齊數(shù))的整數(shù)倍的地址處。
//對(duì)齊數(shù)=編譯器默認(rèn)的一個(gè)對(duì)齊數(shù)與該成員大小的一個(gè)較小值
Vs中默認(rèn)的對(duì)齊數(shù)是8
linux中默認(rèn)的對(duì)齊數(shù)是4
3結(jié)構(gòu)體總大小:最大對(duì)齊數(shù)(每個(gè)成員變量的除了第一個(gè)成員都有一個(gè)對(duì)對(duì)齊數(shù))的整數(shù)倍。(每個(gè)成員變量在對(duì) 齊之后,把成員大小加起來(lái),再擴(kuò)大到最大對(duì)齊數(shù)的整數(shù)倍)
4.如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有對(duì)齊數(shù) (含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍。
聯(lián)合體(union)的內(nèi)存對(duì)齊規(guī)則:
1.聯(lián)合體也是一個(gè)結(jié)構(gòu),聯(lián)和體是共享內(nèi)存的。
2.所以的聯(lián)合體的內(nèi)部成員起始地址都是一樣的,都是聯(lián)合體的首地址。
3.它的對(duì)齊方式要適應(yīng)所有成員。
4.該空間必須足夠容納最寬成員。
5.聯(lián)合體的對(duì)齊數(shù)為最大成員的對(duì)齊數(shù)。
位斷(struct)的內(nèi)存對(duì)齊規(guī)則:
1.如果相鄰位域字段的類型相同,且其位寬之和小于sizeof(type)的大小,則后面的字段緊鄰前一個(gè)字節(jié)存儲(chǔ),直到 容納不下為止;基本成員是連續(xù)存儲(chǔ)的,若這個(gè)單元空間放不下下一個(gè)成員,則新開辟一個(gè)單元空間,這樣可以節(jié) 省內(nèi)存空間。
2.如果相鄰位域字段的類型相同,但其位寬之和大于sizeof(type)的大小,則后面的字段將從新的單元開始,偏移量 為其類型大小的整數(shù)倍。
3.如果相鄰位域字段的類型不相同,則各編譯器的實(shí)現(xiàn)有差異,vc6采取不壓縮方式,Dev-c++采取壓縮。
4.如果位域字段之間穿插著非位域字段,則不進(jìn)行壓縮。
5.結(jié)構(gòu)體的總大小為最大對(duì)齊數(shù)的整數(shù)倍。因?yàn)槲粩喑蓡T必須聲明為int、signed int或unsigned int類型,因此結(jié)構(gòu)體的 大小都是4的整數(shù)倍。
下面我們看一個(gè)代碼,通過(guò)以上規(guī)則計(jì)算其大小結(jié)構(gòu)體,位斷,聯(lián)合體的大小:
在計(jì)算之前,我們首先需要明確的是各個(gè)數(shù)據(jù)成員的對(duì)齊模數(shù),對(duì)齊模數(shù)和數(shù)據(jù)成員本身的長(zhǎng)度以及PRagma pack()編譯參數(shù)有關(guān),#pragma pack(n) 可以設(shè)定對(duì)對(duì)齊數(shù),編譯器支持往比默認(rèn)對(duì)齊數(shù)小的數(shù)調(diào)。對(duì)齊數(shù)=編譯器默認(rèn)的一個(gè)對(duì)齊數(shù)與該成員大小的一個(gè)較小值。如果程序沒有明確指出,就需要知道編譯器默認(rèn)的對(duì)齊模數(shù)值。
下表是Windows xp/DEV-C++和Linux/GCC中基本數(shù)據(jù)類型的長(zhǎng)度和默認(rèn)對(duì)齊模數(shù)。
|
| char | short | int | long | float | double | long long | long double |
Win-32 | 長(zhǎng)度 | 1 | 2 | 4 | 4 | 4 | 8 | 8 | 8 |
模數(shù) | 1 | 2 | 4 | 4 | 4 | 8 | 8 | 8 | |
Linux-32 | 長(zhǎng)度 | 1 | 2 | 4 | 4 | 4 | 8 | 8 | 12 |
模數(shù) | 1 | 2 | 4 | 4 | 4 | 4 | 4 | 4 | |
Linux-64 | 長(zhǎng)度 | 1 | 2 | 4 | 8 | 4 | 8 | 8 | 16 |
模數(shù) | 1 | 2 | 4 | 8 | 4 | 8 | 8 | 16 |
#include<stdio.h>#include<windows.h>#pragma pack(4) //默認(rèn)對(duì)齊數(shù)為4struct A{ char a1; //1+3 char占1個(gè)字節(jié),double要對(duì)齊到4的整數(shù)倍處,所以1+3對(duì)其到4 double a2; //8 int a3; //4}; //結(jié)構(gòu)體總大小:16 對(duì)齊數(shù):4union un{ char b1; //1 struct A b2; //16 int b3; //4}; //聯(lián)合體總大小:16 對(duì)齊數(shù)為:4(最大成員的對(duì)齊數(shù))struct B{ unsigned int c1 : 4; //4 unsigned int c2 : 31; //位域 //4 unsigned int c3 ; //非位域 //4 unsigned int c4 : 1; //4}; //位斷的總大小:16 對(duì)齊數(shù):4 struct obj{ double d1; //8 char d2; //1+3 union un d3; //16 使1+3對(duì)齊到12,即4的整數(shù)倍 struct B d4; //16 char d5; //1+3 使1+3對(duì)齊到48,即4的整數(shù)倍 struct C{ struct B e1;//16 char e2; //1+3 使1+3對(duì)齊到20,即4的整數(shù)倍 double e3; //8 }; //總大小:28 對(duì)齊數(shù):4 char d6; //1+3}; //結(jié)構(gòu)體obj的總大小:80(使1+3對(duì)齊到80,即4的整數(shù)倍) 最大對(duì)齊數(shù):4int main(){ printf("%d/n", sizeof(struct obj)); //結(jié)構(gòu)體obj的總大小:80 system("pause"); return 0;}
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注