C語言中的結構體VS聯合體

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 B{
      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)=10;(大於等於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)對於聯合的不同成員賦值,將會對其它成員重寫,原來成員的值就不存在了,而對於結構體的不同成員賦值是互不影響的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章