c語言中sizeof struct和sizeof union


一般32位機子上各個數據類型所佔的存儲空間如下:

char:8位 

short:16位

int:32位

long:32位

float:32位

double:64位

一、接下來先來看struct,結構體

請牢記以下3條原則:(在沒有#pragma pack宏的情況下)

1、數據成員對齊規則:結構體(struct)的數據成員,第一個數據成員放在offset爲0的地方,之後的每個數據成員存儲的起始位置要從該成員大小的整數倍開始(比如int在32位機子上爲4字節,所以要從4的整數倍地址開始存儲)。

2、結構體作爲成員:如果一個結構體裏同時包含結構體成員,則結構體成員要從其內部最大元素大小的整數倍地址開始存儲(如struct a裏有struct b,b裏有char,int ,double等元素,那麼b應該從8(即double類型的大小)的整數倍開始存儲)。

3、結構體的總大小:即sizeof的結果。在按之前的對齊原則計算出來的大小的基礎上,必須還得是其內部最大成員的整數倍,不足的要補齊(如struct裏最大爲double,現在計算得到的已經是11,則總大小爲16)。

具體例子:

  1. typedef struct bb  
  2. {  
  3.     int id;             //[0]....[3]      表示4字節  
  4.     double weight;      //[8].....[15]      原則1  
  5.     float height;      //[16]..[19],總長要爲8的整數倍,僅對齊之後總長爲[0]~[19]爲20,補齊[20]...[23]     原則3  
  6. }BB;  
<span style="font-size:18px;"><strong>typedef struct bb
{
	int id;             //[0]....[3]      表示4字節
	double weight;      //[8].....[15]      原則1
	float height;      //[16]..[19],總長要爲8的整數倍,僅對齊之後總長爲[0]~[19]爲20,補齊[20]...[23]     原則3
}BB;</strong></span>
  1. typedef struct aa    
  2. {     
  3.     int  id;         //[0]...[3]          原則1    
  4.     double score;     //[8]....[15]        
  5.     short grade;    //[16],[17]            
  6.     BB b;             //[24]......[47]       原則2(因爲BB內部最大成員爲double,即8的整數倍開始存儲)    
  7.     char name[2]; //[48][49]  
  8. }AA;   
<span style="font-size:18px;"><strong>typedef struct aa  
{  	
	int  id;         //[0]...[3]          原則1  
	double score;     //[8]....[15]      
	short grade;    //[16],[17]          
	BB b;             //[24]......[47]       原則2(因爲BB內部最大成員爲double,即8的整數倍開始存儲)  
	char name[2]; //[48][49]
}AA; </strong></span>

  1. int main()  
  2. {  
  3.     cout<<sizeof(AA)<<" "<<sizeof(BB)<<endl;  
  4.     return 0;  
  5. }  
<span style="font-size:18px;"><strong>int main()
{
	cout<<sizeof(AA)<<" "<<sizeof(BB)<<endl;
	return 0;
}</strong></span>
輸出結果爲56 24

以上結果是在沒有#pragma pack(n)宏的情況下,現在來講講關於#pragma pack(n)。

編譯器中提供了#pragma pack(n)來設定變量以n字節對齊方式。//n爲1、2、4、8、16...

n字節對齊就是說變量存放的起始地址的偏移量有兩種情況:第一、如果n大於等於該變量所佔用的字節數,那麼偏移量必須滿足默認的對齊方式,即該變量所佔用字節數的整數倍;第二、如果n小於該變量的類型所佔用的字節數,那麼偏移量爲n的倍數,不用滿足默認的對齊方式。

結構的總大小也有個約束條件,分下面兩種情況:如果n大於所有成員變量類型所佔用的字節數,那麼結構的總大小必須爲佔用空間最大的變量佔用的空間數的倍數;否則必須爲n的倍數。

所以在上面的代碼前加一句#pragma pack(1),

則代碼輸出爲bb:(0~3)+(4~11)+(12~15)=16;aa:(0~3)+(4~11)+(12~13)+(14~29)+(30~31)=32,也就是說,#pragma pack(1)就是沒有對齊規則。

再考慮#pragma pack(4),bb:(0~3)+(4~11)+(12~15)=16;aa:(0~1)+(4~11)+(12~13)+(16~31)+(32~35)=36

二、union共用體(聯合)

共用體表示幾個變量共用一個內存位置,在不同的時間保存不同的數據類型和不同長度的變量。在union中,所有的共用體成員共用一個空間,並且同一時間只能儲存其中一個成員變量的值。當一個共用體被聲明時, 編譯程序自動地產生一個變量, 其長度爲聯合中元類型(如數組,取其類型的數據長度)最大的變量長度的整數倍,且要大於等於其最大成員所佔的存儲空間。
  1. union foo  
  2. {  
  3. char s[10];  
  4. int i;  
  5. }  
<span style="font-size:18px;"><strong>union foo
{
char s[10];
int i;
}</strong></span>
在這個union中,foo的內存空間的長度爲12,是int型的3倍,而並不是數組的長度10。若把int改爲double,則foo的內存空間爲16,是double型的兩倍。
  1. union   mm{    
  2.   char   a;//元長度1        1  
  3.   int   b[5];//元長度4     20  
  4.   double   c;//元長度8     8  
  5.   int   d[3];              12  
  6.   };    
<span style="font-size:18px;"><strong>union   mm{  
  char   a;//元長度1        1
  int   b[5];//元長度4     20
  double   c;//元長度8     8
  int   d[3];              12
  };  
</strong></span>
所以sizeof(mm)=8*3=24;
當在共用體中包含結構體時,如下:
  1. struct inner  
  2. {  
  3.    char      c1;  
  4.    double   d;  
  5.    char     c2;  
  6.   };  
  7.   
  8. union data4  
  9. {  
  10.      struct   inner t1;  
  11.       int           i;  
  12.       char        c;  
  13.     };  
<span style="font-size:18px;"><strong>struct inner
{
   char      c1;
   double   d;
   char     c2;
  };

union data4
{
     struct   inner t1;
      int           i;
      char        c;
    };
</strong></span>
由於data4共用體中有一個inner結構體,所以最大的基本數據類型爲double,因此以8字節對齊。共用體的存儲長度取決於t1,而t1長度爲24,因此sizeof(uniondata4)的值爲24.

當在結構體中包含共用體時,共用體在結構體裏的對齊地址爲共用體本身內部所對齊位數,如下:
  1. typedef union{  
  2.     long i;  
  3.     int k[5];  
  4.     char c;  
  5. }DATE;  
  6. struct data{  
  7.     int cat;  
  8.     char cc;  
  9.     DATE cow;  
  10.     char a[6];  
  11. };  
<span style="font-size:18px;"><strong>typedef union{
	long i;
	int k[5];
	char c;
}DATE;
struct data{
	int cat;
	char cc;
	DATE cow;
	char a[6];
};</strong></span>
sizeof(DATE)=20, 而在結構體中中是4+1+3(補齊4對齊)+20+6+2(補齊4對齊)=36;


三、兩者的區別

1. 共用體和結構體都是由多個不同的數據類型成員組成, 但在任何同一時刻, 共用體只存放了一個被選中的成員, 而結構體的所有成員都存在。
2. 對於共用體的不同成員賦值, 將會對其它成員重寫, 原來成員的值就不存在了, 而對於結構體的不同成員賦值是互不影響的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章