http://www.cnblogs.com/fly1988happy/archive/2012/04/12/2444408.html
做題的時候被記憶體對齊困擾了很久,終于找到一個能讓自己了解透徹的回答,希望對大家有幫助
1.C語言中的結構體
1.1 定義
結構體是由一系列相同或不同類型的變量組成的集合。
struct 結構體名{ //struct為關鍵字,“結構體名”為使用者定義的類型辨別。
資料類型1 成員名1; //{ }中是組成該結構體的成員,其中資料類型可以是C語言所允許的任何資料類型。
資料類型2 成員名2;
...
資料類型n 成員名n;
};
1.2 結構體的記憶體配置設定(方法一)
結構體在記憶體中配置設定一塊連續的記憶體,但結構體内的變量并不一定是連續存放的,這涉及到記憶體對齊。
原則1 資料成員對齊規則:結構(struct或聯合union)的資料成員,第一個資料成員放在offset為0的地方,以後每個資料成員存儲的起始位置要從該成員大小的整數倍開始(比如int在32位機為4位元組,則要從4的整數倍位址開始存儲)。
原則2 結構體作為成員:如果一個結構裡有某些結構體成員,則結構體成員要從其内部最大元素大小的整數倍位址開始存儲。(struct a裡存有struct b,b裡有char,int,double等元素,那b應該從8的整數倍開始存儲。)
原則3 收尾工作:結構體的總大小,也就是sizeof的結果,必須是其内部最大成員的整數倍,不足的要補齊。
例1.
struct A struct
{ {
int a; char b;
char b; int a;
short c; short c;
}; };
sizeof(A) = 8; int為4,char為1,short為2,這裡用到了原則1和原則3。
sizeof(B) = 12; char為1,int為4,short為2,怎麼會是12?還是原則1和原則3。
a b c
A的記憶體布局:1111, 1*, 11
b a c
B的記憶體布局:1***, 1111, 11**
其中星号*表示填充的位元組。
A中,b後面為何要補充一個位元組?因為c為short,其起始位置要為2的倍數,就是原則1。c的後面沒有補充,因為b和c正好占用4個位元組,整個A占用空間為4的倍數,也就是最大成員int類型的倍數,是以不用補充。
B中,b是char為1,b後面補充了3個位元組,因為a是int為4,根據原則1,起始位置要為4的倍數,是以b後面要補充3個位元組。c後面補充兩個位元組,根據原則3,整個B占用空間要為4的倍數,c後面不補充,整個B的空間為10,不符,是以要補充2個位元組。
例2.
struct A struct B
{ {
int a; char e[2];
double b; int f;
float c; double g;
}; short h;
struct A i;
};
sizeof(A) = 24; int為4,double為8,float為4,總長為8的倍數,補齊,是以整個A為24。
sizeof(B) = 48; 看看B的記憶體布局。
e f g h
B的記憶體布局:11* *, 1111, 11111111, 11 * * * * * *,
i
1111* * * *, 11111111, 1111 * * * *
i其實就是A的記憶體布局。根據原則2,i的起始位置要為8的倍數,是以h後面要補齊。
1.3 結構體的記憶體配置設定(方法二)
struct的記憶體大小為每個資料記憶體的加和,首先按照最大的資料類型進行單個配置設定,如果前一個資料占用不了所有的記憶體,而剩下的記憶體可以放下下一個資料,則第二個資料不另外配置設定記憶體(但是位址必須是從這個資料類型大小的整數倍開始,看下面的struct C),否則重新配置設定一個最大類型的記憶體。(個人覺得這種方法比較好了解!)
例3.
struct A struct B struct C
{ { {
int a; int a; int a;
char b; double b; char b;
double c; char c; short c;
}; }; char d;
};
對于結構體A:
因為A中最大的資料類型是double,占8個位元組。是以系統先配置設定8個位元組用來放int,結果int隻需要4個就夠了,然後剩下的4個位元組中的1個可以用來放後面的char,碰到double c時,因為此時的3個位元組不能存下,是以再配置設定了一個8個位元組來存放double c。是以A占用16個位元組。
對于結構體B:
系統碰到int分給他8個位元組存放,碰到double時,剩下的4個位元組不足以存放,是以再配置設定了8個位元組,再遇到char時又配置設定了8個位元組,這樣B共配置設定了24個位元組。(系統其實是浪費了5個位元組的空間)
比較A和B,隻有變量定義的順序不一樣,結果占用的記憶體空間也不一樣。是以,結構體裡面最好按照類型從小到大的順序來排列,以免浪費空間。
對于結構體C:
按照上述方法,最大的資料類型是int,占4個位元組,系統先配置設定4個位元組(0~3);再配置設定4個位元組(4~7),存放char b;short c占2個位元組,但是必須從2的整數倍開始,是以應當配置設定(6~7),中間空餘1個位元組;char d占1個位元組,但是上次配置設定的4位元組用完了,是以需要再配置設定4個位元組存放char d,d隻占用1個位元組,是以剩下3個位元組空閑。sizeof(struct C)=12。
2. C++中的結構體與類的差別
C中的結構體不允許有函數,而C++中的結構體允許。
類與結構體在C++中隻有兩點差別,除此這外無任何差別。
1)class中預設的成員通路權限是private的,而struct中則是public的。
2)從class繼承預設是private繼承,而從struct繼承預設是public繼承。
3. 聯合union
3.1 定義
聯合(又叫共用體)是一種特殊形式的變量,使用關鍵字union來定義 ,它的聲明與變量定義與結構體十分相似。其形式為:
union 聯合名
{
資料類型 成員名;
資料類型 成員名;
...
} 變量名;
聯合表示幾個變量共用一個記憶體位置,在不同的時間儲存不同的資料類型和不同長度的變量。在union中,所有的聯合成員共用一個空間,并且同一時間隻能儲存其中一個成員變量的值。
3.2 聯合的記憶體配置設定
Union的大小為其内部所有變量的最大值,并且按照類型最大值的整數倍進行記憶體對齊。
union A union B union C union D
{ { { {
char c[10]; char c[10]; char c[10]; char c;
char cc1; int i; double d; int i;
}u1; }u2; }u3; double d;
}u4;
union A :首先按照char c[10]配置設定10個位元組,然後按照char的1個位元組對齊,最終sizeof(u1)=10;
union B :首先按照char c[10]配置設定10個位元組,然後按照int的4個位元組對齊,最終sizeof(u2)=12; (大于等于10且能被4整除的最小的數,即12)
union C :首先按照char c[10]配置設定10個位元組,然後按照doube的8個位元組對齊,最終sizeof(u3)=16;(大于等于10且能被8整除的最小的數,即16)
union D:按照double配置設定8個位元組,最終sizeof(u4)=8;
3.3 應用
在C/C++程式的編寫中,當多個基本資料類型或複合資料結構要占用同一片記憶體時,我們要使用聯合體;當多種類型,多個對象,多個事物隻取其一時(我們姑且通俗地稱其為“n 選1”),我們也可以使用聯合體來發揮其長處。
union myun
{
struct
{
int x;
int y;
int z;
}u;
int k;
}a;
int main()
{
a.u.x =4;
a.u.y =5;
a.u.z =6;
a.k = 0;
printf("%d %d %d\n",a.u.x,a.u.y,a.u.z);
return 0;
}
union類型是共享記憶體的,以size最大的結構作為自己的大小,這樣的話,myun這個結構就包含u這個結構體,而大小也等于u這個結構體的大小,在記憶體中的排列為聲明的順序x,y,z從低到高,然後指派的時候,在記憶體中,就是x的位置放置4,y的位置放置5,z的位置放置6,現在對k指派,對k的指派因為是union,要共享記憶體,是以從union的首位址開始放置,首位址開始的位置其實是x的位置,這樣原來記憶體中x的位置就被k所賦的值代替了,就變為0了,這個時候要進行列印,就直接看記憶體裡就行了,x的位置也就是k的位置是0,而y,z的位置的值沒有改變,是以應該是0,5,6。
4.結構體和聯合的差別:
1)聯合和結構體都是由多個不同的資料類型成員組成,但在任何同一時刻,聯合隻存放了一個被選中的成員,而結構體的所有成員都存在。
2)對于聯合的不同成員指派,将會對其它成員重寫,原來成員的值就不存在了,而對于結構體的不同成員指派是互不影響的。