像結(jié)構(gòu)體一樣,聯(lián)合體(Union)在C語言中是一個用戶定義的數(shù)據(jù)類型,用于保存不同類型的元素。
但它并不占所有成員的內(nèi)存總和。它只占最大成員的內(nèi)存,它分享最大成員的內(nèi)存。

聯(lián)合體優(yōu)點
它占用較少的內(nèi)存,因為它只占最大的成員的內(nèi)存量。
聯(lián)合體缺點
它將數(shù)據(jù)存儲在一個成員中。
union關(guān)鍵字用于定義聯(lián)合體。下面我們來看看如何在C語言中定義聯(lián)合體的語法 -
union union_name
{
data_type member1;
data_type member2;
.
.
data_type memeberN;
};
我們來看看在C語言中定義員工聯(lián)合體的例子。如下代碼 -
union employee
{ int id;
char name[50];
float salary;
};
注:除了
union關(guān)鍵字,其它均與結(jié)構(gòu)體一樣。
我們來看看一個簡單的C語言聯(lián)合示例。創(chuàng)建一個源文件:union-example.c,其代碼實現(xiàn)如下 -
#include <stdio.h>
#include <string.h>
union employee
{
int id;
char name[150];
}e1; //declaring e1 variable for union
int main()
{
//store first employee information
e1.id = 1010;
strcpy(e1.name, "Maxsu");//copying string into char array
//printing first employee information
printf("employee 1 id : %d, address: %u\n", e1.id, &e1.id);
printf("employee 1 name : %s, address: %u\n", e1.name, &e1.name);
e1.id = 1010;
printf("employee 1 id : %d, address: %u\n", e1.id, &e1.id);
printf("employee 1 name : %s, address: %u\n", e1.name, &e1.name);
return 0;
}
執(zhí)行上面示例代碼,得到以下結(jié)果 -
employee 1 id : 1937269069, address: 16819328
employee 1 name : Maxsu, address: 16819328
employee 1 id : 1010, address: 16819328
employee 1 name : ?, address: 16819328
如上輸出結(jié)果中可以看到,id字段的值是一個垃圾值,因為name具有大的內(nèi)存大小。所以只有name才具有實際值。
聯(lián)合體完全就是共用一個內(nèi)存首地址,并且各種變量名都可以同時使用,操作也是共同生效。如此多的訪問內(nèi)存手段,確實好用,不過這些“手段”之間卻沒法互相屏蔽——就好像數(shù)組+下標和指針+偏移一樣。
由于聯(lián)合體中的所有成員是共享一段內(nèi)存的,因此每個成員的存放首地址相對于于聯(lián)合體變量的基地址的偏移量為0,即所有成員的首地址都是一樣的。為了使得所有成員能夠共享一段內(nèi)存,因此該空間必須足夠容納這些成員中最寬的成員。對于這句“對齊方式要適合其中所有的成員”是指其必須符合所有成員的自身對齊方式。
下面舉例說明:
union U
{
char s[9];
int n;
double d;
};
s占9字節(jié),n占4字節(jié),d占8字節(jié),因此其至少需9字節(jié)的空間。然而其實際大小并不是9,用運算符sizeof測試其大小為16.這是因為這里存在字節(jié)對齊的問題,9既不能被4整除,也不能被8整除。因此補充字節(jié)到16,這樣就符合所有成員的自身對齊了。從這里可以看出聯(lián)合體所占的空間不僅取決于最寬成員,還跟所有成員有關(guān)系,即其大小必須滿足兩個條件:1)大小足夠容納最寬的成員;2)大小能被其包含的所有基本數(shù)據(jù)類型的大小所整除。
測試程序,創(chuàng)建一個源文件:union-test.c,其代碼實現(xiàn)如下 -
#include <stdio.h>
#include <string.h>
union U1
{
char s[9];
int n;
double d;
}u1;
union U2
{
char s[5];
int n;
double d;
}u2;
int main()
{
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;
}
執(zhí)行上面測試代碼,得到以下結(jié)果 -
16
8
0xeca5a0
0xeca5a0
0xeca5a0
0xeca5a0
1
0.000000
1
0
0
0
0
0
0
0