好的,接下來我們來學習最后一個自定義數據類型——聯合體。
一、什么是聯合體:
聯合體又叫共用體,用關鍵字union來進行定義。又因為所有的成員變量共用同一段內存空間(關于這一點,我們不久就會加以驗證),所以它是一種比較特殊的自定義類型。
二、聯合體的內存布局:
(1)驗證聯合體成員共用同一塊空間:
我們前面已經提到了說聯合體它的成員變量都是共用同一段內存空間的,我們可以通過下面這個代碼對這一結論加以驗證:
#include<stdio.h>
union Uo
{int a;char i;
};
int main()
{union Uo u;printf("sizeof(u) == %zd\n", sizeof(u));printf("%p\n", &(u.a));printf("%p\n", &(u.i));return 0;
}
運行效果:
?
我們發現對于聯合體u,它的大小是4Byte,且無論是針對它的成員變量a取地址,還是針對它的成員變量i取地址,它的結果都是一樣的。
我們可以進一步做一些事情,我們修改變量a的值,然后來觀察成員變量i是否會受影響。因此我們寫出下面這個代碼:
#include<stdio.h>
union Uo
{int a;char i;
};
int main()
{union Uo u;u.a = 0x44332211;//%x是以十六進制打印整數:printf("0x%x\n", u.a);printf("0x%x\n", u.i);return 0;
}
運行結果(注意這里的結果你可能和我不一樣,因為這和機器是小端字節序,還是大端字節序有關系。而博主現在是小端字節序的機器):
?
我們發現對聯合體中某一個成員變量的值進行修改,也會影響到其他的成員變量。這里又進一步佐證了聯合體的成員變量共用同一段內存空間這一事實。
綜上,對于聯合體變量union Uo u來說,它的內存布局是:
(2)聯合體內存大小的計算:
有很多小伙伴在聯合體這里會犯一個錯誤,認為聯合體的大小就是最大成員變量的大小。但是其實不然,就比如說下面這個代碼場景:
#include<stdio.h>
union Uo
{int a;char i[5];
};
int main()
{union Uo u;printf("%zd\n", sizeof(u));return 0;
}
運行結果:
所以關于聯合體的大小:我們認為聯合體的大小至少是最大成員變量的大小。當最大成員變量的大小不是最大對齊數的整數倍時(關于對齊數可以看博主的前面的博客C語言自定義數據類型詳解(二)——結構體類型(下)-CSDN博客)需要進行內存對齊。
三、聯合體的應用場景:
我們試想這么一個場景:我們要求設計一些數據類型來存儲圖書,布袋,襯衫這三個商品的一些屬性。那首先分析這三個商品,它們都有各自以下這些屬性:
圖書:庫存量,價格,書名,作者;
布袋:庫存量,價格,樣式;
襯衫:庫存量,價格,顏色,尺寸;
那據此,你可不可以設計下面這樣的:
struct book
{int _stock; //庫存float _price;//價格char _bookName[30];//書名char _writer[30]; //作者
};
struct bag
{int _stock; //庫存float _price;//價格char _style[30];//樣式
};
struct shirt
{int _stock; //庫存float _price;//價格char color[15];//顏色size_t _size; //尺寸
};
但是你有沒有覺得這個設計比較冗余,因為庫存量和價格都是這些商品共有的屬性。這在C++,Java里面可以通過繼承的方式來消除這種設計上的冗余,那C語言呢?OK,C語言可以借助聯合體設計出下面這個結構體:
#include<stdio.h>
#include<string.h>
struct commodity
{int _stock; //庫存float _price;//價格//這里面都是匿名結構體和匿名聯合體哦!union{struct{char _bookName[30];//書名char _writer[30]; //作者} _book;struct{char _style[30];//樣式} _bag;struct{char color[15];//顏色size_t _size; //尺寸} _shirt;}_item;
};
int main()
{struct commodity com;//注意這里的_writer是char* const的指針(常量指針),所以不能寫作com._item._book._writer = "MoYan";strcpy(com._item._book._writer, "MoYan");printf("The writer of the book is %s\n", com._item._book._writer);return 0;
}
OK,這次的知識分享就到這里了,我們下次再見!