c++ union学习
看到公司前輩的代碼中用到了union,不管是大學還是工作用到union機會比較少,還是挺新奇的.所以特意找些資料學習學習
前輩的代碼:
1 #include<iostream> 2 using namespace std; 3 4 typedef unsigned int UINT32; 5 typedef unsigned char UINT8; 6 typedef unsigned short UINT16; 7 8 union date 9 { 10 UINT32 value; 11 struct 12 { 13 UINT8 day; 14 UINT8 month; 15 UINT16 year; 16 }; 17 }__attribute__((packed)); 18 int main(int argc, char** argv) 19 { 20 date myDate; 21 myDate.day = 02; 22 myDate.month = 10; 23 myDate.year = 2014; 24 cout<<hex<<myDate.value<<dec<<endl; 25 return 0; 26 } 27 //輸出結果 0x7de0a02--->02對應day 0a對應month 7de對應2014 (計算過程 16*16*7+16*13+14)下面是找的學習帖子: ??http://blog.sina.com.cn/s/blog_660234cf0100wsgs.html
union主要是共享內存,分配內存以其最大的結構或對象為大小,即sizeof最大的。在C/C++程序的編寫中,當多個基本數據類型或復合數據結構要占用同一片內存時,我們要使用聯合體;當多種類型,多個對象,多個事物只取其一時(我們姑且通俗地稱其為“n 選1”),我們也可以使用聯合體來發揮其長處。
1 union myun 2 { 3 struct { int x; int y; int z; }u; 4 int k; 5 }a; 6 int main() 7 { 8 a.u.x =4; 9 a.u.y =5; 10 a.u.z =6; 11 a.k = 0; 12 printf("%d %d %d\n",a.u.x,a.u.y,a.u.z); //0 5 6 13 return 0; 14 }myun這個結構就包含u這個結構體,而大小也等于u這個結構體 的大小,在內存中的排列為聲明的順序x,y,z從低到高,然后賦值的時候,在內存中,就是x的位置放置4,y的位置放置5,z的位置放置6,現在對k賦 值,對k的賦值因為是union,要共享內存,所以從union的首地址開始放置,首地址開始的位置其實是x的位置,這樣原來內存中x的位置就被k所賦的 值代替了,就變為0了 再看兩個試題:
試題一:編寫一段程序判斷系統中的CPU 是Little endian 還是Big endian 模式?
分析:
Little endian 和Big endian 是CPU 存放數據的兩種不同順序。對于整型、長整型等數據類型,Big endian 認為第一個字節是最高位字節(按照從低地址到高地址的順序存放數據的高位字節到低位字節);而Little endian 則相反,它認為第一個字節是最低位字節(按照從低地址到高地址的順序存放數據的低位字節到高位字節)。
--------------------------------------------------------------------------------------
例如
------------------------------------------------------------------------------------------------
一般來說,x86 系列CPU 都是little-endian 的字節序,PowerPC 通常是Big endian,還有的CPU 能通過跳線來設置CPU 工作于Little endian 還是Big endian 模式。
解答:
顯然,解答這個問題的方法只能是將一個字節(CHAR/BYTE 類型)的數據和一個整型數據存放于同樣的內存開始地址,通過讀取整型數據,分析CHAR/BYTE 數據在整型數據的高位還是低位來判斷CPU 工作于Littleendian 還是Big endian 模式。得出如下的答案:
int main(int argc, char** argv)
{
int i = 0x12345678;
char* p = reinterpret_cast<char*>(&i);
cout<<hex<<static_cast<int>(*p)<<endl;
return 0;
} ?//如果輸出是78就是小段 ?如果輸出是34就是大端
除了上述方法(通過指針類型強制轉換并對整型數據首字節賦值,判斷該賦值賦給了高位還是低位)外,還有沒
有更好的辦法呢?我們知道,union 的成員本身就被存放在相同的內存空間(共享內存,正是union 發揮作用、做貢獻的去處),因此,我們可以將一個CHAR/BYTE 數據和一個整型數據同時作為一個union 的成員,得出
如下答案:
實現同樣的功能,我們來看看Linux 操作系統中相關的源代碼是怎么做的:
1 static union 2 { 3 char c[4]; 4 unsigned long mylong; 5 } endian_test = {{ 'l', '?', '?', 'b' } }; 6 7 #define ENDIANNESS ((char)endian_test.mylong)Linux 的內核作者們僅僅用一個union 變量和一個簡單的宏定義就實現了一大段代碼同樣的功能!由以上一段代碼我們可以深刻領會到Linux 源代碼的精妙之處!(如果ENDIANNESS=’1’表示系統為little endian,為’b’表示big endian )
-------------------------
試題二:假設網絡節點A 和網絡節點B 中的通信協議涉及四類報文,報文格式為“報文類型字段+報文內容的結構體”,四個報文內容的結構體類型分別為STRUCTTYPE1~ STRUCTTYPE4,請編寫程序以最簡單的方式組織一個統一的報文數據結構。
分析:
報文的格式為“報文類型+報文內容的結構體”,在真實的通信中,每次只能發四類報文中的一種,我們可以將四類報文的結構體組織為一個union(共享一段內存,但每次有效的只是一種),然后和報文類型字段統一組織成一個報文數據結構。
解答:
根據上述分析,我們很自然地得出如下答案:
//統一的報文數據結構
1 typedef struct tagPacket 2 { 3 BYTE pktType; 4 PacketContent pktContent; 5 }Packet;?--------------------------------------------------------------------
繼續學習
http://baike.so.com/doc/200726-212218.html
http://blog.csdn.net/lincyang/article/details/6176642
?首先是union的大小問題
??? 可以看出來union也使用類似struct的內存大小分配方式.
對應union Stu2來說 最大是10 但是最小單位是4 所以會擴展成4*3=12.
union結構體對成員變量的要求:
union的成員不可以為靜態、引用[理由是聯合里面的東西是共享內存的,而靜態和引用不可能共享內存],如果是自訂型態的話,該自訂型態成員不可以有建構函式、解構函式或是復制指定運算子。
以下就是錯誤的形式[理由是帶有構造函數、析夠函數、復制拷貝操作符等的類他們共享內存,編譯器無法保證這些對象不被破壞,也無法保證離開時調用析夠函數。]
當然.如果你不主動提供構造函數,而使用類或者結構體默認的構造函數是可以的.
??
在class中定義union對象
| 錯誤代碼 | 正確代碼 | 原因分析 |
| ? | 錯誤代碼之所以錯誤是因為在構造函數的 初始化列表的時候 根本就還沒有data對象 有何談data的成員變量ch呢 |
如何有效的防止union的訪問錯誤
使用聯合可以節省內存空間,但是也有一定的風險:通過一個不適當的數據成員獲取當前對象的值!例如上面的ch、i交錯訪問。
為了防止這樣的錯誤,我們必須定義一個額外的對象,來跟蹤當前被存儲在聯合中的值得類型,我們稱這個額外的對象為:union的判別式(例如上例中的enum type)。
?一個比較好的經驗是,在處理作為類成員的union對象時,為所有union數據類型提供一組訪問函數。
?
轉載于:https://www.cnblogs.com/silentNight/p/5575780.html
總結
以上是生活随笔為你收集整理的c++ union学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AD Hoc(State 1)
- 下一篇: 动态给src赋值