C語言編程中的聯合體union入門學習教程詳解

聯合體(union)在C語言中是一個特殊的數據類型,能夠存儲不同類型的數據在同一個內存位置。可以定義一個聯合體使用許多成員,但只有一個部件可以包含在任何時候給定的值。聯合體會提供使用相同的存儲器位置供多用途的有效方式。

C語言編程中的聯合體union入門學習教程詳解

定義聯合體

要定義聯合體,必須使用union語句很相似於定義結構。聯合體聲明中定義了一個新的數據類型,程序不止一個成員。聯合體聲明的格式如下:

union [union tag]{ member definition; member definition; ... member definition;} [one or more union variables];

union標籤是可選的,每個成員的定義是一個正常的變量定義,如 int i; 和 float f; 或任何其他有效的變量的定義。在聯合體定義的結尾,最後分號之前,可以指定一個或多個變量的聯合,但它是可選的。這裏定義一個名爲數據聯合類型有三個成員 i, f, 和 str:

union Data{ int i; float f; char str[20];} data;

現在,數據類型的變量可以存儲的整數,一個浮點數,或字符的字符串。這意味着一個單可變結構即相同的存儲單元可用於存儲多個類型的數據。可以使用任何內置或用戶定義的數據類型根據需要在聯合裏面。

通過union所佔用的內存將大到足以容納聯合體的最大成員。例如,在上面的例子中的數據類型將佔用20個字節的存儲空間,因爲這是通過文字串所佔用的最大空間。以下將顯示由上述聯合共佔用內存大小的例子:

#include#includeunion Data{ int i; float f; char str[20];}; int main( ){ union Data data; printf( "Memory size occupied by data : %d", sizeof(data)); return 0;}

讓我們編譯和運行上面的'程序,這將產生以下結果:

Memory size occupied by data : 20

訪問聯合體成員

要訪問聯合體的任何成員,我們使用成員訪問運算符(.)。成員訪問運算符編碼爲聯合體變量名和成員,訪問時使用union關鍵字定義聯合體類型的變量。以下爲例子來解釋聯合體的用法:

#include#includeunion Data{ int i; float f; char str[20];}; int main( ){ union Data data; data.i = 10; data.f = 220.5; strcpy( , "C Programming"); printf( "data.i : %d", data.i); printf( "data.f : %f", data.f); printf( " : %s", ); return 0;}

讓我們編譯和運行上面的程序,這將產生以下結果:

data.i : 1917853763data.f : : C Programming

在這裏,我們可以看到,聯合體成員i 和f 值被損壞,因爲分配給變量終值已佔用的內存位置,如果str成員的值被很好的打印的原因。現在,讓我們來再一次看看同樣的例子,我們將使用一個變量在同一時間,它是聯合體的主要目的:

#include#includeunion Data{ int i; float f; char str[20];}; int main( ){ union Data data; data.i = 10; printf( "data.i : %d", data.i); data.f = 220.5; printf( "data.f : %f", data.f); strcpy( , "C Programming"); printf( " : %s", ); return 0;}

讓我們編譯和運行上面的程序,這將產生以下結果:

data.i : 10data.f : : C Programming

這裏,所有的成員都得到打印得非常好,因爲一個部件被一次使用。

應用場合

當多個數據需要共享內存或者多個數據每次只取其一時,可以利用聯合體(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*/#includeusing 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("%dn",sizeof(u1)); printf("%dn",sizeof(u2)); printf("0x%xn",&u1); printf("0x%xn",&u1.s); printf("0x%xn",&u1.n); printf("0x%xn",&u1.d); u1.n=1; printf("%dn",u1.s[0]); printf("%lfn",u1.d); unsigned char *p=(unsigned char *)&u1; printf("%dn",*p); printf("%dn",*(p+1)); printf("%dn",*(p+2)); printf("%dn",*(p+3)); printf("%dn",*(p+4)); printf("%dn",*(p+5)); printf("%dn",*(p+6)); printf("%dn",*(p+7)); return 0;}

輸出結果爲:

1680x22ff600x22ff600x22ff600x22ff6010.000000100048204640請按任意鍵繼續. . .

對於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

對於double型數據,第63位0爲符號位,62-52 00000000100爲階碼,0000 11001100 00110000 00000000 00000000 00000000 00000001爲尾數,根據其值知道尾數值約爲0,而階碼爲4-1023=-1019,因此其表示的浮點數爲1.0*2^(-1019)=0.00000000000......,因此輸出結果爲0.000000。