1. 程式人生 > >淺談C語言中的聯合體

淺談C語言中的聯合體

      當多個數據需要共享記憶體或者多個數據每次只取其一時,可以利用聯合體(union)。在C Programming Language 一書中對於聯合體是這麼描述的:

     1)聯合體是一個結構;

     2)它的所有成員相對於基地址的偏移量都為0;

     3)此結構空間要大到足夠容納最"寬"的成員;

     4)其對齊方式要適合其中所有的成員;

下面解釋這四條描述:

     由於聯合體中的所有成員是共享一段記憶體的,因此每個成員的存放首地址相對於於聯合體變數的基地址的偏移量為0,即所有成員的首地址都是一樣的。為了使得所有成員能夠共享一段記憶體,因此該空間必須足夠容納這些成員中最寬的成員。對於這句“對齊方式要適合其中所有的成員”是指其必須符合所有成員的自身對齊方式。

下面舉例說明:

如聯合體

union U{ char s[9]; int n; double d;};

s佔9位元組,n佔4位元組,d佔8位元組,因此其至少需9位元組的空間。然而其實際大小並不是9,用運算子sizeof測試其大小為16.這是因為這裡存在位元組對齊的問題,9既不能被4整除,也不能被8整除。因此補充位元組到16,這樣就符合所有成員的自身對齊了。從這裡可以看出聯合體所佔的空間不僅取決於最寬成員,還跟所有成員有關係,即其大小必須滿足兩個條件:1)大小足夠容納最寬的成員;2)大小能被其包含的所有基本資料型別的大小所整除。

測試程式:

複製程式碼 /*測試聯合體 2011.10.3*/

#include <iostream>
using
 namespace std;

union U1
{
char s[9];
int n;
double d;
};

union U2
{
char s[5];
int n;
double d;
};

int main(int argc, char *argv[])
{
U1 u1;
U2 u2;
printf("%d\n",sizeof(u1));
printf("%d\n",sizeof(u2));
printf("0x%x\n",&u1);
printf("0x%x\n",&u1.s);
printf("0x%x\n",&u1.n);
printf("0x%x\n",&u1.d);
u1.n=1
;
printf("%d\n",u1.s[0]);
printf("%lf\n",u1.d);
unsigned char *p=(unsigned char *)&u1;
printf("%d\n",*p);
printf("%d\n",*(p+1));
printf("%d\n",*(p+2));
printf("%d\n",*(p+3));
printf("%d\n",*(p+4));
printf("%d\n",*(p+5));
printf("%d\n",*(p+6));
printf("%d\n",*(p+7));
return 0;
} 複製程式碼


輸出結果為:

16
8
0x22ff60
0x22ff60
0x22ff60
0x22ff60
1
0.000000
1
0
0
0
48
204
64
0
請按任意鍵繼續. . .

對於sizeof(u1)=16。因為u1中s佔9位元組,n佔4位元組,d佔8位元組,因此至少需要9位元組。其包含的基本資料型別為char,int,double分別佔1,4,8位元組,為了使u1所佔空間的大小能被1,4,8整除,則需填充位元組以到16,因此sizeof(u1)=16.

對於sizeof(u2)=8。因為u2中s佔5位元組,n佔4位元組,d佔8位元組,因此至少需要8位元組。其包含的基本資料型別為char,int,double分別佔1,4,8位元組,為了使u2所佔空間的大小能被1,4,8整除,不需填充位元組,因為8本身就能滿足要求。因此sizeof(u2)=8。

從打印出的每個成員的基地址可以看出,聯合體中每個成員的基地址都相同,等於聯合體變數的首地址。

對u1.n=1,將u1的n賦值為1後,則該段記憶體的前4個位元組儲存的資料為00000001 00000000 00000000 00000000

因此取s[0]的資料表示取第一個單元的資料,其整型值為1,所以打印出的結果為1.

至於打印出的d為0.000000願意如下。由於已知該段記憶體前4位元組的單元儲存的資料為00000001 00000000 00000000 00000000,從上面列印結果48,204,64,0可以知道後面4個位元組單元中的資料為00110000 11001100 01000000 00000000,因此其表示的二進 制浮點數為

00000000 01000000 11001100 00110000 00000000 00000000 00000000 00000001