結構體變量的成員在內存裏是如何分佈的、成員前後順序是怎樣的、成員之間是連續的仍是分散的、仍是其餘的什麼形式?這些問題既和軟件相關又和硬件相關。所謂軟件相關主要是指和具體的編程語言的編譯器的特性相關,編譯器爲了優化CPU訪問內存的效率,在生成結構體成員的起始地址時遵循着某種特定的規則,這就是所謂的 結構體成員「對齊」;所謂硬件相關主要是指CPU的「字節序」問題,也就是大於一個字節類型的數據如int類型、short類型等,在內存中的存放順序,即單個字節與高低地址的對應關係。編程
(1)爲了提升CPU訪問內存的效率,程序語言的編譯器在作變量的存儲分配時進行了優化處理,處理的原則是:對於n字節的元素,它的首地址能被n整除,這種原則稱爲「對齊」。數組
(2)結構體(聯合體)的成員所佔內存地址依次增高,第一個成員位於低地址處,最後一個成員位於高地址處,可是結構體成員的內存並非連續的,編譯器會對成員作上述「對齊」處理。編程語言
(3)一般編譯器能夠設置一個對齊參數n,結構體中每一個成員實際對齊參數N根據N=min(sizeof(成員類型),n)來獲得。結構體成員的內存偏移地址x,知足條件x%N=0。優化
(4)結構體全部成員的對齊參數N的最大值稱爲結構體的對齊參數。整個結構的長度必須是結構體對齊參數的最小整數倍,不夠補0。spa
簡單來講:code
1)結構體的起始地址爲x,x%sizeof(結構體)=0。blog
2)結構體每一個成員相對於起始地址偏移地址y,y%N=0。內存
3)結構體長度等於結構體對齊參數的最小整數倍。編譯器
注:編譯器對齊參數能夠經過指令控制,例如#param pack(2)兩字節對齊。vs2010IDE還能夠經過"項目屬性"->"C/C++"->"代碼生成"->「結構成員對齊」來設置。編譯器默認對齊參數爲8個字節。it
例:
struct A { char c; //1byte double d; //8byte short s; //2byte int i; //4byte }; int main(int argc, char*argv[]) { A strua; printf("len:%d\n",sizeof(A)); printf("%d,%d,%d,%d",&strua.c,&strua.d,&strua.s,&strua.i); return 0; }
輸出結果爲:
len:24
1506156,1506164,1506172,1506176
(1)結構體成員爲數組時,是將數組的每一個元素當一個成員來分配,並非將整個數組當成一個成員來對待。其餘成員的分配規則按照上述規則。
(2)當結構體成員是位段時,存儲是按其類型分配空間的,如int型的位段就分配4個字節的存儲單元。相鄰的同類型的兩個位段,若是該類型的長度夠用,就將兩位段連續存放,共用存儲單元,若是不夠用,就另起一個該類型長度的存儲空間。相鄰的不一樣類型的兩個位段,分別爲這兩個位段分配它們所屬類型長度的存儲空間。其餘成員的分配規則按照上述規則。
1)例1:
struct bit { int a:3; int b:2; int c:3; }; int main(int argc,char* argv[]) { bit s; char *c = (char*)&s; *c = 0x99; cout<<s.a<<endl<<s.b<<endl<<s.c<<endl; return 0; }
輸出結果: 1 -1 -4
分析:
hex 0x99
bin 100 11 001
c b a
地址 高 --> 低
cpu爲小端模式,高位比特存儲在高地址中,低位比特存儲在低地址中。並且計算機中存儲的是數的補碼形式。
2)例2:
struct bit { char a:5; char b:4; char c:7; }; int main(int argc,char* argv[]) { bit s; int *c = (int*)&s; *c = 0x99E00000; cout<<sizeof(bit)<<endl<<(int)s.a<<endl<<(int)s.b<<endl<<(int)s.c<<endl; return 0; }
輸出結果:3 0 0 -32
hex 0x99 0xE0 0x00 0x00
bin 10011001 11100000 00000000 00000000
c b a
地址 高 --> 低