C語(yǔ)言聯(lián)合體的實(shí)現(xiàn)示例
一、聯(lián)合體類型的聲明
聯(lián)合體也是一種自定義類型。像結(jié)構(gòu)體一樣,聯(lián)合體也是由一個(gè)或者多個(gè)成員構(gòu)成,這些成員可以是不同的類型。
但是編譯器只為最大的成員分配足夠的內(nèi)存空間。聯(lián)合體的特點(diǎn)是所有成員共用同一塊內(nèi)存空間。所以聯(lián)合體也叫:共用體。聯(lián)合體類型的定義形式:

- union是聯(lián)合體關(guān)鍵字
- tag是標(biāo)簽名,是自定義的
- union tag就是聯(lián)合體類型
- { }放的是成員列表
- member1,member2是聯(lián)合體成員
- variable-list是變量名
來(lái)看下面一段代碼:
#include <stdio.h>
//聯(lián)合體類型的聲明
union Un
{
char c;
int i;
};
int main()
{
union Un un = { 0 };//聯(lián)合變量的初始化
printf("%d\n", sizeof(un));//計(jì)算聯(lián)合變量的??
return 0;
}
程序運(yùn)行結(jié)果:

通過(guò)計(jì)算得到聯(lián)合體變量un的大小為4(單位字節(jié))。為什么是這個(gè)值呢?
二、聯(lián)合體的特點(diǎn)
剛剛我們說(shuō)過(guò)聯(lián)合體的所有成員是共用一塊內(nèi)存空間的,這樣一個(gè)聯(lián)合體變量的大小,至少是最大成員的大小(因?yàn)槁?lián)合體至少得有能力保存最大的那個(gè)成員)。我們?cè)賮?lái)看兩段代碼:
//代碼1
#include <stdio.h>
//聯(lián)合類型的聲明
union Un
{
char c;
int i;
};
int main()
{
//聯(lián)合變量的定義
union Un un = { 0 };
//下?輸出的結(jié)果是?樣的嗎?
printf("%p\n", &(un.i));
printf("%p\n", &(un.c));
printf("%p\n", &un);
return 0;
}
程序運(yùn)行結(jié)果:

//代碼2
#include <stdio.h>
//聯(lián)合類型的聲明
union Un
{
char c;
int i;
};
int main()
{
//聯(lián)合變量的定義
union Un un = { 0 };
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i);
return 0;
}
程序運(yùn)行結(jié)果:

通過(guò)代碼1的運(yùn)行結(jié)果可知,輸出的三個(gè)地址一模一樣,而通過(guò)代碼2的運(yùn)行結(jié)果,我們發(fā)現(xiàn)變量i的值變成了0x11223355。我們仔細(xì)分析就可以畫出,un的內(nèi)存布局圖。

由上圖,這里是小端字節(jié)序存儲(chǔ),為聯(lián)合變量un的成員i開辟了4個(gè)字節(jié)的空間來(lái)存儲(chǔ)數(shù)據(jù)0x11223344。而當(dāng)我們緊接著為該聯(lián)合變量un的成員c賦值0x55時(shí),發(fā)現(xiàn)原來(lái)成員i存儲(chǔ)的四個(gè)字節(jié)數(shù)據(jù)的低位字節(jié)數(shù)據(jù)的44被修改為了55(這里只修改了i成員的一個(gè)字節(jié)數(shù)據(jù),因?yàn)槌蓡Tc是char類型,只占一個(gè)字節(jié),所以i只被覆蓋了一個(gè)字節(jié))??吹竭@里應(yīng)該就明白了,那就是聯(lián)合體的成員是共用一塊內(nèi)存空間。對(duì)其中一個(gè)成員進(jìn)行賦值修改時(shí),再修改其他成員的值,那原來(lái)成員存儲(chǔ)的值就會(huì)被剛剛修改的成員值所覆蓋掉。所以對(duì)于聯(lián)合體在同一時(shí)間最好是只使用一個(gè)成員。
上面我們計(jì)算過(guò)這個(gè)聯(lián)合體類型union Un的大小為4,因?yàn)檫@個(gè)聯(lián)合體類型有兩個(gè)成員:一個(gè)是char類型的,一個(gè)是int類型的。則要先保證能存儲(chǔ)最大的那個(gè)成員,其次小的成員是和這個(gè)最大的成員共用同一塊內(nèi)存空間的,所以這里計(jì)算出該聯(lián)合體類型的大小就為4。
相同成員的結(jié)構(gòu)體和聯(lián)合體對(duì)比
struct S
{
char c;
int i;
};
struct S s = {0};
計(jì)算該結(jié)構(gòu)體的大小為:

union Un
{
char c;
int i;
};
union Un un = { 0 };
計(jì)算聯(lián)合體的大小為:

我們畫出上面的結(jié)構(gòu)體和聯(lián)合體的內(nèi)存布局示意圖進(jìn)行對(duì)比:

對(duì)于結(jié)構(gòu)體來(lái)說(shuō),成員c和i是有自己獨(dú)立的空間的,而對(duì)于聯(lián)合體來(lái)說(shuō)成員c和i是共用同一塊內(nèi)存空間的,這是它們之間的區(qū)別。所以對(duì)于結(jié)構(gòu)體和聯(lián)合體來(lái)說(shuō),它們是有各自的應(yīng)用場(chǎng)景的。
三、聯(lián)合體大小的計(jì)算
聯(lián)合體的大小可不是就像上面說(shuō)的一樣,就是最大成員的大小,不是這么簡(jiǎn)單的。那只是其中一條規(guī)則:??● 聯(lián)合的大小至少得是最大成員的大小。??● 聯(lián)合體的大小必須是最大對(duì)齊數(shù)的整數(shù)倍。當(dāng)最大成員的大小不是最大對(duì)齊數(shù)的整數(shù)倍的時(shí)候,就要對(duì)齊到最大對(duì)齊數(shù)的整數(shù)倍。
在計(jì)算結(jié)構(gòu)體大小時(shí),是有最大對(duì)齊數(shù)的,那在計(jì)算聯(lián)合體大小時(shí)也是有最大對(duì)齊數(shù)的。找對(duì)齊數(shù)的規(guī)則,跟結(jié)構(gòu)體中是一樣的。上面的第二條規(guī)則是啥意思?我們通過(guò)下面的例子來(lái)講解:
#include<stdio.h>
union Un1
{
int i;
char c;
short arr1[7];
};
union Un2
{
char c;
int i;
int arr2[3];
};
union Un3
{
char arr3[5];
int i;
double d;
};
int main()
{
union Un1 un1 = { 0 };
union Un2 un2 = { 0 };
union Un3 un3 = { 0 };
printf("%zd\n", sizeof(un1));
printf("%zd\n", sizeof(un2));
printf("%zd\n", sizeof(un3));
return 0;
}
程序運(yùn)行結(jié)果:

先看第一個(gè)聯(lián)合體變量un1,他的成員中最大成員的大小是4,可能會(huì)有同學(xué)在有數(shù)組成員的地方犯迷糊,搞不清楚數(shù)組成員到底要怎么計(jì)算最大對(duì)齊數(shù)?其實(shí)很簡(jiǎn)單,首先我們知道數(shù)組在內(nèi)存中是連續(xù)存放的,數(shù)組的大小就等于 元素個(gè)數(shù)*元素類型的大小。就像這里的聯(lián)合變量un1中數(shù)組成員arr1的大小就是7*sizeof(short)=14(單位字節(jié))。找數(shù)組成員的對(duì)齊數(shù),其實(shí)就看數(shù)組單個(gè)元素類型的大小與編譯器默認(rèn)對(duì)齊數(shù)的較小值即可。所以對(duì)于聯(lián)合變量un1的最大對(duì)齊數(shù)就為4:

那這里最大成員的大小就是14,而14并不是最大對(duì)齊數(shù)的整數(shù)倍,所以還要再浪費(fèi)2個(gè)字節(jié),到16就是4的倍數(shù)了,所以聯(lián)合變量un1的大小就為16。
再看第二個(gè)聯(lián)合變量un2,該變量三個(gè)成員中的最大對(duì)齊數(shù)是4,第三個(gè)成員數(shù)組arr2的大小為3*sizeof(int)=12,而12正好是最大對(duì)齊數(shù)4的倍數(shù),所以該聯(lián)合變量un2的大小就為12。
最后第三個(gè)聯(lián)合變量un3,該變量的三個(gè)成員中最大對(duì)齊數(shù)是8,第一個(gè)成員數(shù)組arr3的大小為5*sizeof(char)=5,這里最大的成員就是數(shù)組arr3,但是5不是最大對(duì)齊數(shù)8的整數(shù)倍,還要再浪費(fèi)3個(gè)字節(jié),到8就是8的倍數(shù)了。
聯(lián)合體的應(yīng)用案例
使用聯(lián)合體是可以節(jié)省空間的,下面的一個(gè)案例可以說(shuō)明:
比如,我們要搞一個(gè)活動(dòng),要上線一個(gè)禮品兌換單,禮品兌換單中有三種商品:圖書、杯子、襯衫。每一種商品都有:庫(kù)存量、價(jià)格、商品類型和商品類型相關(guān)的其他信息。

如果我們采用結(jié)構(gòu)體的形式來(lái)包裝上面的屬性:
struct gift_list
{
//公共屬性
int stock_number;//庫(kù)存量
double price; //定價(jià)
int item_type;//商品類型
//特殊屬性
char title[20];//書名
char author[20];//作者
int num_pages;//?數(shù)
char design[30];//設(shè)計(jì)
int colors;//顏?
int sizes;//尺寸
};
上面的結(jié)構(gòu)其實(shí)設(shè)計(jì)的很簡(jiǎn)單,用起來(lái)也方便,但是結(jié)構(gòu)的設(shè)計(jì)中包含了所有禮品的各種屬性,這樣使得結(jié)構(gòu)體的大小就會(huì)偏大(因?yàn)榻Y(jié)構(gòu)體中的成員都是有自己獨(dú)立的空間的),比較浪費(fèi)內(nèi)存。因?yàn)閷?duì)于禮品兌換單中的商品來(lái)說(shuō),只有部分屬性信息是常用的。比如:商品是圖書,那就不需要design、colors、sizes這幾個(gè)特殊屬性了。
所以我們就可以把公共屬性單獨(dú)寫出來(lái),剩余屬于各種商品本身的屬性用聯(lián)合體包裝起來(lái),這樣就可以減少所需的內(nèi)存空間,一定程度上節(jié)省了內(nèi)存。
struct gift_list
{
int stock_number;//庫(kù)存量
double price; //定價(jià)
int item_type;//商品類型
union
{
struct
{
char title[20];//書名
char author[20];//作者
int num_pages;//?數(shù)
}book;
struct
{
char design[30];//設(shè)計(jì)
}mug;
struct
{
char design[30];//設(shè)計(jì)
int colors;//顏?
int sizes;//尺?
}shirt;
}item;
};
上面的特殊屬性就放在了聯(lián)合體中,因?yàn)槊縿?chuàng)建一個(gè)商品變量時(shí),只會(huì)用到聯(lián)合體中的其中一個(gè)結(jié)構(gòu)體成員,而聯(lián)合體中的成員是共用同一塊內(nèi)存空間的,所以這里大大的節(jié)省了內(nèi)存空間。這就是聯(lián)合體的好處。(上面的結(jié)構(gòu)體中的聯(lián)合體成員及其內(nèi)部的結(jié)構(gòu)體成員都是采用匿名的,意思是這個(gè)聯(lián)合變量只會(huì)被使用一次)
用聯(lián)合體判斷當(dāng)前機(jī)器是小端還是大端
????聯(lián)合體還可以用來(lái)判斷當(dāng)前自己使用的機(jī)器平臺(tái)是大端字節(jié)序存儲(chǔ)還是小端字節(jié)序存儲(chǔ),小端和大端字節(jié)序存儲(chǔ)是什么意思?比如我們創(chuàng)建了一個(gè)整型變量 i 存儲(chǔ)了0x00000001這樣一個(gè)值,那請(qǐng)問這個(gè)值在內(nèi)存中的排放順序是什么?是低位的值開從低地址處開始存放呢,還是低位的值從高地址處開始存放呢?

通過(guò)使用聯(lián)合體就可以知道當(dāng)前機(jī)器是小端還是大端:
#include<stdio.h>
int check_sys()
{
union
{
int i;
char c;
}un;
un.i = 1;
return un.c;//返回1是?端,返回0是?端
}
int main()
{
printf("%d\n", check_sys());
return 0;
}
程序運(yùn)行結(jié)果:

我們可以逐語(yǔ)句(F11)調(diào)試起來(lái),在內(nèi)存中查看聯(lián)合變量un存儲(chǔ)的值,就是因?yàn)樵诼?lián)合體中變量i和變量c是共用同一塊內(nèi)存空間的,所以在對(duì)整型變量i賦值1后,我們就可以通過(guò)字符類型(1個(gè)字節(jié))的變量c查看在低位字節(jié)的值是不是1來(lái)判斷當(dāng)前機(jī)器是小端還是大端。

通過(guò)上圖可以看出,我使用的機(jī)器平臺(tái)采用的是小端字節(jié)序存儲(chǔ)(低位從低地址處開始存放)。
到此這篇關(guān)于C語(yǔ)言聯(lián)合體的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)C語(yǔ)言聯(lián)合體內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C語(yǔ)言編程中的聯(lián)合體union入門學(xué)習(xí)教程
- C語(yǔ)言中聯(lián)合體union的實(shí)例詳解
- C語(yǔ)言中枚舉與聯(lián)合體的使用方法(enum union)
- C語(yǔ)言結(jié)構(gòu)體,枚舉,聯(lián)合體詳解
- C語(yǔ)言關(guān)于自定義數(shù)據(jù)類型之枚舉和聯(lián)合體詳解
- C語(yǔ)言超詳細(xì)講解結(jié)構(gòu)體與聯(lián)合體的使用
- C語(yǔ)言枚舉與聯(lián)合體深入詳解
- C語(yǔ)言中聯(lián)合體與共用體和枚舉使用語(yǔ)法示例
- c語(yǔ)言中聯(lián)合體和枚舉用法詳解
- C語(yǔ)言聯(lián)合體類型的實(shí)現(xiàn)
- 一文帶你認(rèn)識(shí)C語(yǔ)言的聯(lián)合體和枚舉
相關(guān)文章
C++11 線程同步接口std::condition_variable和std::future的簡(jiǎn)單使用示例詳
本文介紹了std::condition_variable和std::future在C++中的應(yīng)用,用于線程間的同步和異步執(zhí)行,通過(guò)示例代碼,展示了如何使用std::condition_variable的wait和notify接口進(jìn)行線程間同步2024-09-09
C++數(shù)據(jù)結(jié)構(gòu)哈希表詳解
C++標(biāo)準(zhǔn)庫(kù)中使用的unordered_map底層實(shí)現(xiàn)是哈希表,下面這篇文章主要給大家介紹了關(guān)于C++中使用哈希表(unordered_map)的一些常用操作方法,需要的朋友可以參考下2022-07-07
詳解C語(yǔ)言中不同類型的數(shù)據(jù)轉(zhuǎn)換規(guī)則
這篇文章給大家講解不同類型數(shù)據(jù)間的混合運(yùn)算與類型轉(zhuǎn)換,有自動(dòng)類型轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換,針對(duì)每種轉(zhuǎn)換方法小編給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-07-07
C語(yǔ)言中socket相關(guān)網(wǎng)絡(luò)編程函數(shù)小結(jié)
這篇文章主要介紹了C語(yǔ)言中socket相關(guān)網(wǎng)絡(luò)編程函數(shù)小結(jié),是C語(yǔ)言入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09
Qt數(shù)據(jù)庫(kù)應(yīng)用之實(shí)現(xiàn)通用數(shù)據(jù)生成器
有兩種應(yīng)用場(chǎng)景需要用到數(shù)據(jù)生成器,一種是需要測(cè)試數(shù)據(jù)庫(kù)性能,一種是隨機(jī)模擬生成一堆數(shù)據(jù),用來(lái)測(cè)試程序的性能。本文將利用Qt實(shí)現(xiàn)通用數(shù)據(jù)生成器,需要的可以參考一下2022-02-02
Qt利用QDrag實(shí)現(xiàn)拖拽拼圖功能詳解
QDrag類為MIME-based拖拽數(shù)據(jù)轉(zhuǎn)換提供支持。本文為大家主要介紹如何利用QDrag類實(shí)現(xiàn)拖拽拼圖功能。左邊是打散的圖,拖動(dòng)到右邊進(jìn)行復(fù)現(xiàn),此外程序還支持手動(dòng)拖入原圖片,感興趣的可以了解一下2022-07-07

