C語言共用體(Union)
阿新 • • 發佈:2019-01-27
通過前面的講解,我們知道結構體(Struct)是一種構造型別或複雜型別,它可以包含多個型別不同的成員。在C語言中,還有另外一種和結構體非常類似的語法,叫做共用體(Union),它的定義格式為:
結構體佔用的記憶體大於等於所有成員佔用的記憶體的總和(成員之間可能會存在縫隙),共用體佔用的記憶體等於最長的成員佔用的記憶體。共用體使用了記憶體覆蓋技術,同一時刻只能儲存一個成員的值,如果對新的成員賦值,就會把原來成員的值覆蓋掉。
共用體也是一種自定義型別,可以通過它來建立變數,例如:
要想理解上面的輸出結果,弄清成員之間究竟是如何相互影響的,就得了解各個成員在記憶體中的分佈。以上面的 data 為例,各個成員在記憶體中的分佈如下:
成員 n、ch、m 在記憶體中“對齊”到一頭,對 ch 賦值修改的是前一個位元組,對 m 賦值修改的是前兩個位元組,對 n 賦值修改的是全部位元組。也就是說,ch、m 會影響到 n 的一部分資料,而 n 會影響到 ch、m 的全部資料。
上圖是在絕大多數 PC 機上的記憶體分佈情況,如果是 51 微控制器,情況就會有所不同:
為什麼不同的機器會有不同的分佈情況呢?這跟機器的儲存模式有關,我們將在VIP教程《大端小端以及判別方式》一節中展開探討。
f 和 m 分別表示女性和男性,s 表示學生,t 表示教師。可以看出,學生和教師所包含的資料是不同的。現在要求把這些資訊放在同一個表格中,並設計程式輸入人員資訊然後輸出。
如果把每個人的資訊都看作一個結構體變數的話,那麼教師和學生的前 4 個成員變數是一樣的,第 5 個成員變數可能是 score 或者 course。當第 4 個成員變數的值是 s 的時候,第 5 個成員變數就是 score;當第 4 個成員變數的值是 t 的時候,第 5 個成員變數就是 course。
經過上面的分析,我們可以設計一個包含共用體的結構體,請看下面的程式碼:
union 共用體名{
成員列表
};
共用體有時也被稱為聯合或者聯合體,這也是 Union 這個單詞的本意。結構體和共用體的區別在於:結構體的各個成員會佔用不同的記憶體,互相之間沒有影響;而共用體的所有成員佔用同一段記憶體,修改一個成員會影響其餘所有成員。
結構體佔用的記憶體大於等於所有成員佔用的記憶體的總和(成員之間可能會存在縫隙),共用體佔用的記憶體等於最長的成員佔用的記憶體。共用體使用了記憶體覆蓋技術,同一時刻只能儲存一個成員的值,如果對新的成員賦值,就會把原來成員的值覆蓋掉。
共用體也是一種自定義型別,可以通過它來建立變數,例如:
- union data{
- int n;
- char ch;
- double f;
- };
- union dataa, b, c;
- union data{
- int n;
- char ch;
- double f;
- } a, b, c;
- union data{
- int n;
- char ch;
- double f;
- } a, b, c;
- #include <stdio.h>
- union data{
- int n;
- char ch;
- short m;
- };
- int main(){
- union dataa;
- printf("%d, %d\n", sizeof(a), sizeof(union data) );
- a.n = 0x40;
- printf("%X, %c, %hX\n", a.n, a.ch, a.m);
- a.ch = '9';
- printf("%X, %c, %hX\n", a.n, a.ch, a.m);
- a.m = 0x2059;
- printf("%X, %c, %hX
- a.n = 0x3E25AD54;
- printf("%X, %c, %hX\n", a.n, a.ch, a.m);
- return 0;
- }
4, 4 40, @, 40 39, 9, 39 2059, Y, 2059 3E25AD54, T, AD54這段程式碼不但驗證了共用體的長度,還說明共用體成員之間會相互影響,修改一個成員的值會影響其他成員。
要想理解上面的輸出結果,弄清成員之間究竟是如何相互影響的,就得了解各個成員在記憶體中的分佈。以上面的 data 為例,各個成員在記憶體中的分佈如下:
成員 n、ch、m 在記憶體中“對齊”到一頭,對 ch 賦值修改的是前一個位元組,對 m 賦值修改的是前兩個位元組,對 n 賦值修改的是全部位元組。也就是說,ch、m 會影響到 n 的一部分資料,而 n 會影響到 ch、m 的全部資料。
上圖是在絕大多數 PC 機上的記憶體分佈情況,如果是 51 微控制器,情況就會有所不同:
為什麼不同的機器會有不同的分佈情況呢?這跟機器的儲存模式有關,我們將在VIP教程《大端小端以及判別方式》一節中展開探討。
共用體的應用
共用體在一般的程式設計中應用較少,在微控制器中應用較多。對於 PC 機,經常使用到的一個例項是: 現有一張關於學生資訊和教師資訊的表格。學生資訊包括姓名、編號、性別、職業、分數,教師的資訊包括姓名、編號、性別、職業、教學科目。請看下面的表格:Name | Num | Sex | Profession | Score / Course |
---|---|---|---|---|
HanXiaoXiao | 501 | f | s | 89.5 |
YanWeiMin | 1011 | m | t | math |
LiuZhenTao | 109 | f | t | English |
ZhaoFeiYan | 982 | m | s | 95.0 |
f 和 m 分別表示女性和男性,s 表示學生,t 表示教師。可以看出,學生和教師所包含的資料是不同的。現在要求把這些資訊放在同一個表格中,並設計程式輸入人員資訊然後輸出。
如果把每個人的資訊都看作一個結構體變數的話,那麼教師和學生的前 4 個成員變數是一樣的,第 5 個成員變數可能是 score 或者 course。當第 4 個成員變數的值是 s 的時候,第 5 個成員變數就是 score;當第 4 個成員變數的值是 t 的時候,第 5 個成員變數就是 course。
經過上面的分析,我們可以設計一個包含共用體的結構體,請看下面的程式碼:
- #include <stdio.h>
- #include <stdlib.h>
- #define TOTAL 4 //人員總數
- struct{
- char name[20];
- int num;
- char sex;
- char profession;
- union{
- float score;
- char course[20];
- } sc;
- } bodys[TOTAL];
- int main(){
- int i;
- //輸入人員資訊
- for(i=0; i<TOTAL; i++){
- printf("Input info: ");
- scanf("%s %d %c %c", bodys[i].name, &(bodys[i].num), &(bodys[i].sex), &(bodys[i].profession));
- if(bodys[i].profession == 's'){ //如果是學生
- scanf("%f", &bodys[i].sc.score);
- }else{ //如果是老師
- scanf("%s", bodys[i].sc.course);
- }
- fflush(stdin);
- }
- //輸出人員資訊
- printf("\nName\t\tNum\tSex\tProfession\tScore / Course\n");
- for(i=0; i<TOTAL; i++){
- if(bodys[i].profession == 's'){ //如果是學生
- printf("%s\t%d\t%c\t%c\t\t%f\n", bodys[i].name, bodys[i].num, bodys[i].sex, bodys[i].profession, bodys[i].sc.score);
- }else{ //如果是老師
- printf("%s\t%d\t%c\t%c\t\t%s\n", bodys[i].name, bodys[i].num, bodys[i].sex, bodys[i].profession, bodys[i].sc.course);
- }
- }
- return 0;
- }
Input info: HanXiaoXiao 501 f s 89.5↙ Input info: YanWeiMin 1011 m t math↙ Input info: LiuZhenTao 109 f t English↙ Input info: ZhaoFeiYan 982 m s 95.0↙ Name Num Sex Profession Score / Course HanXiaoXiao 501 f s 89.500000 YanWeiMin 1011 m t math LiuZhenTao 109 f t English ZhaoFeiYan 982 m s 95.000000