數(shù)據(jù)結(jié)構(gòu) -- 共用體Union

數(shù)據(jù)結(jié)構(gòu) -- 結(jié)構(gòu)體Struct一文中詳細(xì)介紹了結(jié)構(gòu)體的定義以及內(nèi)存對齊。在C語言中梅割,還有另外一種和結(jié)構(gòu)體非常類似的語法,叫做共用體Union)凡桥,也稱為聯(lián)合體。它的定義格式為:

union 共用體名{
    成員列表
};

1. 定義共用體變量

和結(jié)構(gòu)體一樣蚀同,共用體也是一種自定義的數(shù)據(jù)類型缅刽,是創(chuàng)建變量的模板,不占用內(nèi)存空間唤崭。共用體變量才包含了實(shí)實(shí)在在的數(shù)據(jù)拷恨,需要內(nèi)存空間來存儲。共用體可以通過下面兩種方式來定義:

  • 方式一:先定義共用體谢肾,再定義共用體變量
//定義data共用體
union data{
    int n;
    char ch;
    double f;
};

//定義兩個(gè)共用體變量
union data a, b;

data為共用體名,里面包含n小泉、ch芦疏、f這3個(gè)成員冕杠。ab則為兩個(gè)data類型的共用體變量酸茴。

  • 方式二:在定義共用體的同時(shí)定義共用體變量
union data{
    int n;
    char ch;
    double f;
} a, b;

直接將變量放在共用體的最后即可分预。

如果只需要 a、b兩個(gè)變量薪捍,后面不需要再使用共用體名定義其他變量笼痹,那么在定義時(shí)也可以省略共用體名。

2. 成員的獲取和賦值

共用體使用了內(nèi)存覆蓋機(jī)制酪穿,同一時(shí)刻只能保存一個(gè)成員的值凳干,如果對新的成員賦值,就會把原來成員的值覆蓋掉被济。所以共用體不能整體賦值救赐,只能使用點(diǎn)號.獲取單個(gè)成員,然后再進(jìn)行賦值操作只磷。

//注:下面每一次賦值后经磅,n、ch钮追、f三個(gè)變量的值均會改變
a.n = 40;
a.ch = '9';
a.f = 135;

3. 共用體的內(nèi)存分配

共用體變量占用的內(nèi)存大小等于最長的成員占用的內(nèi)存大小预厌,各成員都會從offset為0處開始存放,修改其中一個(gè)成員會影響其余所有成員元媚。來看下面的實(shí)例:

//定義一個(gè)data共用體
union data{
    int n;
    char ch;
    short m;
};

int main(){
     
    //創(chuàng)建一個(gè)共用體變量a
    union data a;
    printf("a.size = %d, data.size = %d\n", sizeof(a), sizeof(union data) );
    //對成員a賦值
    a.n = 0x40;
    printf("n = %#X, ch = %c, m = %#hX\n",  a.n, a.ch, a.m);
    //對成員b賦值
    a.ch = '9';
    printf("n = %#X, ch = %c, m = %#hX\n", a.n, a.ch, a.m);
    //對成員c賦值
    a.m = 0x2059;
    printf("n = %#X, ch = %c, m = %#hX\n", a.n, a.ch, a.m);
   //再對成員a賦值
    a.n = 0x3E25AD54;
    printf("n = %#X, ch = %c, m = %#hX\n", a.n, a.ch, a.m);
   
    return 0;
}

在上面代碼中創(chuàng)建了一個(gè)共用體變量a轧叽,里面有n、ch惠毁、m這三種不同數(shù)據(jù)類型的成員犹芹,分別對齊賦值,打印每一次賦值后的三個(gè)成員鞠绰。

%X:表示將int類型數(shù)據(jù)以大寫字母的形式輸出十六位進(jìn)制數(shù)腰埂。
%c:表示輸出字符。
%hX:表示將short類型數(shù)據(jù)以大寫字母的形式輸出十六位進(jìn)制數(shù)蜈膨。
#:表示輸出時(shí)加上前綴屿笼,用于區(qū)分不同進(jìn)制的數(shù)字。比如:0x16翁巍,不加#時(shí)輸出為16驴一,加上輸出為0x16。

打印結(jié)果為:

a.size = 4, data.size = 4
n = 0X40, ch = @, m = 0X40
n = 0X39, ch = 9, m = 0X39
n = 0X2059, ch = Y, m = 0X2059
n = 0X3e25ad54, ch = T, m = 0XAD54

從打印結(jié)果可知灶壶,共用體a的內(nèi)存等于其最長成員int n所占的內(nèi)存大小肝断,為4字節(jié)。每次修改共用體中的某個(gè)成員,都會影響到其他成員的值胸懈。

4. 分析共用體的內(nèi)存分配

共用體的每個(gè)成員都從其內(nèi)存offset為0的地方存放担扑,根據(jù)成員數(shù)據(jù)類型各占用對應(yīng)字節(jié)大小的內(nèi)存,每次為成員賦值時(shí)趣钱,都會覆蓋修改所占內(nèi)存涌献,因此,其他成員的值也跟著變動(dòng)了首有。以上面的共存體變量a為例燕垃,分別對其成員賦值,內(nèi)存空間的變化情況就如下圖所示:

圖1 → 圖2 → 圖3 → 圖4 → 圖5

圖1:表示共用體a及其成員的內(nèi)存分配情況:

  • 每一格代表一個(gè)字節(jié)井联,從上到下表示地址由低到高分布卜壕。
  • a總共4字節(jié),成員n低矮、m印叁、ch均從offset為0的地方開始存放,分別占用4字節(jié)军掂、2字節(jié)轮蜕、1字節(jié)的內(nèi)存大小,內(nèi)存存在重合部分蝗锥。

圖2:表示當(dāng)賦值a.n = 0x40后跃洛,共用體a的內(nèi)存空間變化:

1byte = 8bit,所以1個(gè)字節(jié)最大值為255终议,換算成十六進(jìn)制為0xFF汇竭,而0x40小于0xFF,所以只需一個(gè)字節(jié)保存穴张。存儲系統(tǒng)的分布方式大多采用小端模式细燎,即在內(nèi)存的第一個(gè)字節(jié)里保存0x40,此時(shí)成員n皂甘、ch玻驻、m的值均為0x40。

存儲系統(tǒng)分布方式偿枕,以0x12345678為例:
1.大端模式:高位在低地址璧瞬,低位在高地址。即12在低地址渐夸,78在高地址嗤锉。
2.小端模式:高位在高地址,低位在低地址墓塌。即12在高地址瘟忱,78在低地址奥额。

因此,當(dāng)賦值a.n = 0x40后酷誓,打印結(jié)果為:n = 0X40, ch = @, m = 0X40披坏。(0x40對應(yīng)的字符為@

圖3:表示當(dāng)賦值a.ch = '9'后态坦,共用體a的內(nèi)存空間變化:

字符9的十六進(jìn)制ASCII碼值為0x39盐数,在賦值后,內(nèi)存里第一個(gè)字節(jié)的0x40被覆蓋伞梯,變?yōu)?x39玫氢。

因此當(dāng)賦值a.ch = '9'后,打印結(jié)果為:n = 0X39, ch = 9, m = 0X39谜诫。

圖4:表示當(dāng)賦值a.m = 0x2059后漾峡,共用體a的內(nèi)存空間變化:

由于0x2059小于0xFFFF,所以需要兩個(gè)字節(jié)來保存喻旷,在賦值后生逸,內(nèi)存里第一個(gè)字節(jié)里的39被覆蓋,前兩個(gè)字節(jié)分別保存0x59且预、0x20槽袄。

因此當(dāng)賦值a.m = 0x2059后,ch為0x59锋谐,對應(yīng)字符Y遍尺,所以打印結(jié)果為:n = 0X2059, ch = Y, m = 0X2059。

圖5:表示當(dāng)賦值a.n = 0x3E25AD54后涮拗,共用體a的內(nèi)存空間變化:

由于0x3E25AD54小于0xFFFFFFFF乾戏,所以需要4字節(jié)來保存。在賦值后三热,內(nèi)存的4個(gè)字節(jié)分別保存54鼓择、AD、25就漾、3E呐能。

因此當(dāng)賦值a.n = 0x3E25AD54后,ch為0x54从藤,對應(yīng)字符T催跪,m為0xAD54,所以打印結(jié)果為:n = 0X3E25AD54, ch = T, m = 0XAD54夷野。

5. 共用體和結(jié)構(gòu)體的區(qū)別
  • 結(jié)構(gòu)體的第一個(gè)成員會從offset為0的地方開始存放懊蒸,其它成員按順序存儲,各成員會占用不同的內(nèi)存悯搔,互相之間沒有影響骑丸;
    共用體的所有成員都會從offset為0的地方存放,各成員內(nèi)存會存在重,修改一個(gè)成員會影響其余所有成員通危。

  • 結(jié)構(gòu)體占用的內(nèi)存大于等于所有成員占用的內(nèi)存的總和(成員之間可能會存在縫隙)铸豁。
    共用體占用的內(nèi)存等于最長的成員占用的內(nèi)存。共用體使用了內(nèi)存覆蓋技術(shù)菊碟,同一時(shí)刻只能保存一個(gè)成員的值节芥,如果對新的成員賦值,就會把原來成員的值覆蓋掉逆害。

推薦閱讀

1. 數(shù)據(jù)結(jié)構(gòu) -- 結(jié)構(gòu)體Struct
2. 數(shù)據(jù)結(jié)構(gòu) -- 位域

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末头镊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子魄幕,更是在濱河造成了極大的恐慌相艇,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纯陨,死亡現(xiàn)場離奇詭異坛芽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)翼抠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門咙轩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人机久,你說我怎么就攤上這事臭墨。” “怎么了膘盖?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵胧弛,是天一觀的道長。 經(jīng)常有香客問我侠畔,道長结缚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任软棺,我火速辦了婚禮红竭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘喘落。我一直安慰自己茵宪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布瘦棋。 她就那樣靜靜地躺著稀火,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赌朋。 梳的紋絲不亂的頭發(fā)上凰狞,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天篇裁,我揣著相機(jī)與錄音,去河邊找鬼赡若。 笑死达布,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的逾冬。 我是一名探鬼主播黍聂,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粉渠!你這毒婦竟也來了分冈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤霸株,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后集乔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體去件,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年扰路,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尤溜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡汗唱,死狀恐怖宫莱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哩罪,我是刑警寧澤授霸,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站际插,受9級特大地震影響碘耳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜框弛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一辛辨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瑟枫,春花似錦斗搞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至景殷,卻和暖如春溅呢,著一層夾襖步出監(jiān)牢的瞬間澡屡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工咐旧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留驶鹉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓铣墨,卻偏偏與公主長得像室埋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子伊约,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350