C union(聯合體)作用——玩轉 union

C語言中,union相對於struct使用的次數在大部分項目中都處於明顯的劣勢,這和union的存儲方式的特性有很大的關係。在union中,所有的字段都有相同的偏移量,而且所有的字段都是相互重疊的,union的大小是其中最大字段的大小。那我們就知道,如果所有的字段是相互重疊的,那改變其中任何一個字段的值,其他字段的值都會受到影響,也會發生變化。這就造成union在實際使用中使用的頻率不會那麼高,甚至會認爲可能也沒有什麼用。如果想要使用的話,那麼union中的各個字段的使用必須是互斥的,任意時刻只能使用一個。在閱讀《編程卓越之道》有看到union的一些作用,感覺確實可以一用,有一種豁然開朗的感覺。我整理一下《編程卓越之道》的內容和我自己的理解。

1 判斷大小端,union大顯身手
我記得union的第一個作用就是判斷機器的大小端了,當時畢業找工作,很多公司都喜歡出這道題。一個整數在大小端機器上面存儲的順序是不一樣,而union中的各個字段的偏移地址是相同的,那一個數在在大小端機器中存儲到union中,如果將這個數拆分,各個部分也會不同。直接看例子吧,代碼勝於雄辯。

typedef union {
unsigned long bits32;
unsigned char bytes[4];
} TheValue;
TheValue theValue;
int isLittleEndian = 0; 
theValue.bytes[0] = 0;
theValue.bytes[1] = 1;
theValue.bytes[2] = 0;
theValue.bytes[3] = 0;
isLittleEndian = (theValue.bits32 == 256);

2 創建別名
就是這個感覺非常有用,因爲程序中經常會進行類型的強制轉換,如果不小心可能就會出錯,那麼我們就可以利用union中的字段代表想要得到的類型,尤其是指針類型,尤其是代碼整合過程中,如果使用了第三方的庫,需要將第三方的庫merge到自己的代碼中,由於編碼習慣,命名規則的不同,還是需要將其他庫的一些類型轉換爲自己習慣的方式或者公司的方式。一般情況我們是能看到庫的header file的,結構類型什麼的都可以看到。我們會按照庫的header file寫一份自己的。
例如庫中header file有一個struct 名字是ThirdTest
那麼我們header file有一個對應的struct 名字是OurTestThird
那麼就可以弄一個union

typedef union {
    ThirdTest * thirdTest;
    OurTestThird *ourTestThird;
} TestThird;

那我們使用一下

TestThird testThird;
testThird.thirdTest = getCallOneFunction(); //這個一個庫函數,返回的類型是ThirdTest *
CallOurSomeOneFunction(testThird. ourTestThird); //這個是自己的函數,參數類型是OurTestThird *

那這個union TestThird就起到了將類型ThirdTest *強轉爲OurTestThird *的作用,union起到了一個橋樑的作用和粘合劑的作用,不然就需要一個表將自己的類型和庫的類型一一對應起來。
當然這個例子有些牽強,有很多辦法將類型對應起來,這裏只是針對別名列舉一個例子而已。

3 將union中較大的對象分解成組成這個對象的各個字節。
直接看例子吧,這個是完全利用union的存儲特性實現的。來自於《編程卓越之道》。

typedef union {
unsiged int u;
unsiged char bytes[4];
} asBytes;
asBytes composite;
composite.u = 1234576890;
printf (“HO byte of composite.u is %u, LO byte is %u\n”, composite.bytes[3], composite.bytes[0]);

4 其他
Union和struct結合使用是最常見的使用方法。
舉一個例子不知道是否恰當。例如一個系統分爲上中下三層,上層和下層是對應的,而中間層是一個轉換層(傳輸層),也就是說上層可能有A和B兩個不同的系統,下層有C和D兩個系統,而中層E是唯一的,E能保證A和C,B和D正常運行。假設A需要向C傳入一個struct爲StructAC類型的數據,B向D傳入一個struct爲StructBD類型的數據,而E作爲中間層要能夠保證傳輸StructAC和StructBD類型的數據,那中間層E就可以定義一個union

typedef union {
StructAC ac;
StructBD bd;
} UnionE;

E接收到上層的數據後,把數據封裝成UnionE 類型的data,E向下層傳輸就直接傳輸UnionE的data,而下層C和D就可以直接轉爲StructAC和StructBD處理就好了。(A向E,B向E不是直接傳輸的StructAC,StructBD類型的數據,可能是一些原始數據,E需要一些邏輯將這些原始數據轉爲UnionE)

當我們遇到一個新的知識點的時候,可能理解很快,但是瞭解其真實的意圖還是要多看多學,不斷的積累,才能不斷豐富自己的眼界。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章