聯(lián)合(union)
聯(lián)合(union)在許多其他語言中被稱為變體記錄(variant record)。它的外表與結(jié)構(gòu)體相似礁芦,但在內(nèi)存布局上存在關(guān)鍵性的區(qū)別犀忱。在結(jié)構(gòu)體中,每個成員依次存儲彭沼,而在聯(lián)合中,所有的成員都從偏移地址零開始存儲备埃。這樣姓惑,每個成員的位置都重疊在一起;在某一時刻按脚,只有一個成員真正存儲于該地址于毙。
聯(lián)合既有一些優(yōu)點,也有一些缺點辅搬。它的缺點就是那些所謂的優(yōu)點其實并不怎么出色唯沮。聯(lián)合的優(yōu)點是它的外觀同結(jié)構(gòu)體一樣,只是用關(guān)鍵字union取代了關(guān)鍵字struct堪遂。所以介蛉,如果你對結(jié)構(gòu)體的一切都已了如指掌,基本上也就掌握了聯(lián)合溶褪。聯(lián)合的一般形式如下:
union 聯(lián)合標(biāo)簽(可選){
類型1 標(biāo)識符1币旧;
類型2 標(biāo)識符2;
...
類型N 標(biāo)識符N;
}變量定義(可選);
聯(lián)合一般是作為大型結(jié)構(gòu)的一部分存在的猿妈。在有些大型結(jié)構(gòu)中吹菱,存在一些與實際表示的數(shù)據(jù)類型有關(guān)的隱式或顯式的信息。如果存儲數(shù)據(jù)時是一種類型彭则,但在提取該數(shù)據(jù)時卻成了另外一種類型鳍刷,這顯然存在著明顯的類型不安全性。在Ada語言中俯抖,所有不同類型的字段都顯式的存儲于記錄中倾剿,這就避免了這個問題。C語言則含糊的多蚌成,讓程序員自己去回憶放在那兒的究竟是什么東西前痘。
聯(lián)合一般用來節(jié)省空間,因為有些數(shù)據(jù)項是不可能同時出現(xiàn)的担忧,如果同時存儲它們芹缔,顯然頗為浪費(fèi)。例如瓶盛,如果我們要存儲一些關(guān)于動物種類的信息最欠,首先想到的方法可能是:
struct creature{
char has_backbone;
char has_fur;
short num_of_legs_in_excess_of_4;
};
但是示罗,我們知道,所有的動物要么是脊椎動物芝硬,要么是無脊椎動物蚜点。進(jìn)而,我們還知道只有脊椎動物才可能有毛皮拌阴,只有無脊椎動物才可能有多于4條的腿绍绘。沒有一種動物既有毛皮又有超過4條的腿。這樣迟赃,可以通過把兩個互相排斥的字段存儲于一個聯(lián)合中來節(jié)省空間:
union secondary_characteristics{
char has_fur;
short num_of_legs_in_excess_of_4;
};
struct creature{
char has_backbone;
union secondary_characteristics form;
};
我們通常采取這種方式來節(jié)省備用的存儲空間陪拘。如果我們有一個數(shù)據(jù)文件,里面存儲了20000000個動物纤壁,使用這種方法左刽,可以節(jié)省大約20MB的磁盤空間。
然而酌媒,聯(lián)合還有其他用途欠痴,聯(lián)合也可以把同一個數(shù)據(jù)解釋成兩種不同的東西,而不是把兩個不同的數(shù)據(jù)解釋為一個東西秒咨。該用法例子如下:
union bits32_tag{
int whole; //一個32位的值
struct { char c0, c1, c2, c3;} bytes; //4個8位的字節(jié)
} value喇辽;
這個聯(lián)合允許程序員提取整個32位值(作為 int),也可以提取單獨的字節(jié)字段如value.bytes.c0等。采用其他的方法也能達(dá)到這個目的拭荤,但聯(lián)合不需要額外的賦值或強(qiáng)制類型轉(zhuǎn)換。
在實際工作中疫诽,結(jié)構(gòu)體的使用比聯(lián)合多得多舅世。
枚舉(enum)
枚舉(enum)通過一種簡單的途徑,把一串名字與一串整型值聯(lián)系在一起奇徒。對于像C這樣的弱類型語言而言雏亚,很少有什么事只能靠枚舉而不能用#define來解決的。枚舉的一般形式:
enum 可選標(biāo)簽 {內(nèi)容...} 可選變量定義摩钙;
其中的“內(nèi)容...”是把一些標(biāo)識符的列表罢低,可能有一些整型值賦給它們。下面是一個枚舉實例:
enum sizes { small = 7, medium, large = 10, humungous };
缺省情況下胖笛,整型值從0開始网持。如果對列表中的某個標(biāo)識符進(jìn)行了賦值,那么緊接其后的那個標(biāo)識符的值就比所賦的值大1长踊,然后類推功舀。枚舉具有一個優(yōu)點:#define 定義的名字一般在編譯時被丟棄,而枚舉名字則通常一直在調(diào)試器中可見身弊,可以在調(diào)試代碼時使用它們辟汰。