C語言聯(lián)合體的實現(xiàn)示例
一、聯(lián)合體類型的聲明
聯(lián)合體也是一種自定義類型。像結(jié)構(gòu)體一樣,聯(lián)合體也是由一個或者多個成員構(gòu)成,這些成員可以是不同的類型。
但是編譯器只為最大的成員分配足夠的內(nèi)存空間。聯(lián)合體的特點是所有成員共用同一塊內(nèi)存空間。所以聯(lián)合體也叫:共用體。聯(lián)合體類型的定義形式:
- union是聯(lián)合體關(guān)鍵字
- tag是標簽名,是自定義的
- union tag就是聯(lián)合體類型
- { }放的是成員列表
- member1,member2是聯(lián)合體成員
- variable-list是變量名
來看下面一段代碼:
#include <stdio.h> //聯(lián)合體類型的聲明 union Un { char c; int i; }; int main() { union Un un = { 0 };//聯(lián)合變量的初始化 printf("%d\n", sizeof(un));//計算聯(lián)合變量的?? return 0; }
程序運行結(jié)果:
通過計算得到聯(lián)合體變量un的大小為4(單位字節(jié))。為什么是這個值呢?
二、聯(lián)合體的特點
剛剛我們說過聯(lián)合體的所有成員是共用一塊內(nèi)存空間的,這樣一個聯(lián)合體變量的大小,至少是最大成員的大小(因為聯(lián)合體至少得有能力保存最大的那個成員)。我們再來看兩段代碼:
//代碼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; }
程序運行結(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; }
程序運行結(jié)果:
通過代碼1的運行結(jié)果可知,輸出的三個地址一模一樣,而通過代碼2的運行結(jié)果,我們發(fā)現(xiàn)變量i的值變成了0x11223355。我們仔細分析就可以畫出,un的內(nèi)存布局圖。
由上圖,這里是小端字節(jié)序存儲,為聯(lián)合變量un的成員i開辟了4個字節(jié)的空間來存儲數(shù)據(jù)0x11223344。而當我們緊接著為該聯(lián)合變量un的成員c賦值0x55時,發(fā)現(xiàn)原來成員i存儲的四個字節(jié)數(shù)據(jù)的低位字節(jié)數(shù)據(jù)的44被修改為了55(這里只修改了i成員的一個字節(jié)數(shù)據(jù),因為成員c是char類型,只占一個字節(jié),所以i只被覆蓋了一個字節(jié))。看到這里應(yīng)該就明白了,那就是聯(lián)合體的成員是共用一塊內(nèi)存空間。對其中一個成員進行賦值修改時,再修改其他成員的值,那原來成員存儲的值就會被剛剛修改的成員值所覆蓋掉。所以對于聯(lián)合體在同一時間最好是只使用一個成員。
上面我們計算過這個聯(lián)合體類型union Un的大小為4,因為這個聯(lián)合體類型有兩個成員:一個是char類型的,一個是int類型的。則要先保證能存儲最大的那個成員,其次小的成員是和這個最大的成員共用同一塊內(nèi)存空間的,所以這里計算出該聯(lián)合體類型的大小就為4。
相同成員的結(jié)構(gòu)體和聯(lián)合體對比
struct S { char c; int i; }; struct S s = {0};
計算該結(jié)構(gòu)體的大小為:
union Un { char c; int i; }; union Un un = { 0 };
計算聯(lián)合體的大小為:
我們畫出上面的結(jié)構(gòu)體和聯(lián)合體的內(nèi)存布局示意圖進行對比:
對于結(jié)構(gòu)體來說,成員c和i是有自己獨立的空間的,而對于聯(lián)合體來說成員c和i是共用同一塊內(nèi)存空間的,這是它們之間的區(qū)別。所以對于結(jié)構(gòu)體和聯(lián)合體來說,它們是有各自的應(yīng)用場景的。
三、聯(lián)合體大小的計算
聯(lián)合體的大小可不是就像上面說的一樣,就是最大成員的大小,不是這么簡單的。那只是其中一條規(guī)則:??● 聯(lián)合的大小至少得是最大成員的大小。??● 聯(lián)合體的大小必須是最大對齊數(shù)的整數(shù)倍。當最大成員的大小不是最大對齊數(shù)的整數(shù)倍的時候,就要對齊到最大對齊數(shù)的整數(shù)倍。
在計算結(jié)構(gòu)體大小時,是有最大對齊數(shù)的,那在計算聯(lián)合體大小時也是有最大對齊數(shù)的。找對齊數(shù)的規(guī)則,跟結(jié)構(gòu)體中是一樣的。上面的第二條規(guī)則是啥意思?我們通過下面的例子來講解:
#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; }
程序運行結(jié)果:
先看第一個聯(lián)合體變量un1,他的成員中最大成員的大小是4,可能會有同學(xué)在有數(shù)組成員的地方犯迷糊,搞不清楚數(shù)組成員到底要怎么計算最大對齊數(shù)?其實很簡單,首先我們知道數(shù)組在內(nèi)存中是連續(xù)存放的,數(shù)組的大小就等于 元素個數(shù)*元素類型的大小。就像這里的聯(lián)合變量un1中數(shù)組成員arr1的大小就是7*sizeof(short)=14(單位字節(jié))。找數(shù)組成員的對齊數(shù),其實就看數(shù)組單個元素類型的大小與編譯器默認對齊數(shù)的較小值即可。所以對于聯(lián)合變量un1的最大對齊數(shù)就為4:
那這里最大成員的大小就是14,而14并不是最大對齊數(shù)的整數(shù)倍,所以還要再浪費2個字節(jié),到16就是4的倍數(shù)了,所以聯(lián)合變量un1的大小就為16。
再看第二個聯(lián)合變量un2,該變量三個成員中的最大對齊數(shù)是4,第三個成員數(shù)組arr2的大小為3*sizeof(int)=12,而12正好是最大對齊數(shù)4的倍數(shù),所以該聯(lián)合變量un2的大小就為12。
最后第三個聯(lián)合變量un3,該變量的三個成員中最大對齊數(shù)是8,第一個成員數(shù)組arr3的大小為5*sizeof(char)=5,這里最大的成員就是數(shù)組arr3,但是5不是最大對齊數(shù)8的整數(shù)倍,還要再浪費3個字節(jié),到8就是8的倍數(shù)了。
聯(lián)合體的應(yīng)用案例
使用聯(lián)合體是可以節(jié)省空間的,下面的一個案例可以說明:
比如,我們要搞一個活動,要上線一個禮品兌換單,禮品兌換單中有三種商品:圖書、杯子、襯衫。每一種商品都有:庫存量、價格、商品類型和商品類型相關(guān)的其他信息。
如果我們采用結(jié)構(gòu)體的形式來包裝上面的屬性:
struct gift_list { //公共屬性 int stock_number;//庫存量 double price; //定價 int item_type;//商品類型 //特殊屬性 char title[20];//書名 char author[20];//作者 int num_pages;//?數(shù) char design[30];//設(shè)計 int colors;//顏? int sizes;//尺寸 };
上面的結(jié)構(gòu)其實設(shè)計的很簡單,用起來也方便,但是結(jié)構(gòu)的設(shè)計中包含了所有禮品的各種屬性,這樣使得結(jié)構(gòu)體的大小就會偏大(因為結(jié)構(gòu)體中的成員都是有自己獨立的空間的),比較浪費內(nèi)存。因為對于禮品兌換單中的商品來說,只有部分屬性信息是常用的。比如:商品是圖書,那就不需要design、colors、sizes這幾個特殊屬性了。
所以我們就可以把公共屬性單獨寫出來,剩余屬于各種商品本身的屬性用聯(lián)合體包裝起來,這樣就可以減少所需的內(nèi)存空間,一定程度上節(jié)省了內(nèi)存。
struct gift_list { int stock_number;//庫存量 double price; //定價 int item_type;//商品類型 union { struct { char title[20];//書名 char author[20];//作者 int num_pages;//?數(shù) }book; struct { char design[30];//設(shè)計 }mug; struct { char design[30];//設(shè)計 int colors;//顏? int sizes;//尺? }shirt; }item; };
上面的特殊屬性就放在了聯(lián)合體中,因為每創(chuàng)建一個商品變量時,只會用到聯(lián)合體中的其中一個結(jié)構(gòu)體成員,而聯(lián)合體中的成員是共用同一塊內(nèi)存空間的,所以這里大大的節(jié)省了內(nèi)存空間。這就是聯(lián)合體的好處。(上面的結(jié)構(gòu)體中的聯(lián)合體成員及其內(nèi)部的結(jié)構(gòu)體成員都是采用匿名的,意思是這個聯(lián)合變量只會被使用一次)
用聯(lián)合體判斷當前機器是小端還是大端
????聯(lián)合體還可以用來判斷當前自己使用的機器平臺是大端字節(jié)序存儲還是小端字節(jié)序存儲,小端和大端字節(jié)序存儲是什么意思?比如我們創(chuàng)建了一個整型變量 i 存儲了0x00000001這樣一個值,那請問這個值在內(nèi)存中的排放順序是什么?是低位的值開從低地址處開始存放呢,還是低位的值從高地址處開始存放呢?
通過使用聯(lián)合體就可以知道當前機器是小端還是大端:
#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; }
程序運行結(jié)果:
我們可以逐語句(F11)調(diào)試起來,在內(nèi)存中查看聯(lián)合變量un存儲的值,就是因為在聯(lián)合體中變量i和變量c是共用同一塊內(nèi)存空間的,所以在對整型變量i賦值1后,我們就可以通過字符類型(1個字節(jié))的變量c查看在低位字節(jié)的值是不是1來判斷當前機器是小端還是大端。
通過上圖可以看出,我使用的機器平臺采用的是小端字節(jié)序存儲(低位從低地址處開始存放)。
到此這篇關(guān)于C語言聯(lián)合體的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)C語言聯(lián)合體內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C語言編程中的聯(lián)合體union入門學(xué)習(xí)教程
- C語言中聯(lián)合體union的實例詳解
- C語言中枚舉與聯(lián)合體的使用方法(enum union)
- C語言結(jié)構(gòu)體,枚舉,聯(lián)合體詳解
- C語言關(guān)于自定義數(shù)據(jù)類型之枚舉和聯(lián)合體詳解
- C語言超詳細講解結(jié)構(gòu)體與聯(lián)合體的使用
- C語言枚舉與聯(lián)合體深入詳解
- C語言中聯(lián)合體與共用體和枚舉使用語法示例
- c語言中聯(lián)合體和枚舉用法詳解
- C語言聯(lián)合體類型的實現(xiàn)
- 一文帶你認識C語言的聯(lián)合體和枚舉
相關(guān)文章
C++11 線程同步接口std::condition_variable和std::future的簡單使用示例詳
本文介紹了std::condition_variable和std::future在C++中的應(yīng)用,用于線程間的同步和異步執(zhí)行,通過示例代碼,展示了如何使用std::condition_variable的wait和notify接口進行線程間同步2024-09-09C++數(shù)據(jù)結(jié)構(gòu)哈希表詳解
C++標準庫中使用的unordered_map底層實現(xiàn)是哈希表,下面這篇文章主要給大家介紹了關(guān)于C++中使用哈希表(unordered_map)的一些常用操作方法,需要的朋友可以參考下2022-07-07詳解C語言中不同類型的數(shù)據(jù)轉(zhuǎn)換規(guī)則
這篇文章給大家講解不同類型數(shù)據(jù)間的混合運算與類型轉(zhuǎn)換,有自動類型轉(zhuǎn)換和強制類型轉(zhuǎn)換,針對每種轉(zhuǎn)換方法小編給大家介紹的非常詳細,需要的朋友參考下吧2021-07-07C語言中socket相關(guān)網(wǎng)絡(luò)編程函數(shù)小結(jié)
這篇文章主要介紹了C語言中socket相關(guān)網(wǎng)絡(luò)編程函數(shù)小結(jié),是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-09-09Qt數(shù)據(jù)庫應(yīng)用之實現(xiàn)通用數(shù)據(jù)生成器
有兩種應(yīng)用場景需要用到數(shù)據(jù)生成器,一種是需要測試數(shù)據(jù)庫性能,一種是隨機模擬生成一堆數(shù)據(jù),用來測試程序的性能。本文將利用Qt實現(xiàn)通用數(shù)據(jù)生成器,需要的可以參考一下2022-02-02