對union的進一步認識與一些深層應用

來源:互聯網
上載者:User
雖然平時在程式開發時較少使用union ,雖然當初學C語言時 ,union一章被老師略過沒有介紹 ,雖然 ,自認為自己對union的認識已經足夠 ,但是 ,在寫完上一篇文章 <(大衛的閱讀筆記 )C ++中使用union的幾點思考 >之後 ,網上的討論驅使我對這一基本的語言特性又投入了一些精力去關注 ,並寫成了此文 .

下面以MSDN中關於union的概述作為開頭,這好像有些無聊,不過,有時候看specification的東西可以給我們很多提示,當我們從應用的角度去關注一樣東西的時候,很多更深層次的考慮被我們忽略了.所以,看下去,裡面有些東西可能正是你忽略了的.

union
union [tag] { member-list } [declarators];

[union] tag declarators;

The union keyword declares a union type and/or a variable of a union type.

A union is a user-defined data type that can hold values of different types at different times. It is similar to a structure
except that all of its members start at the same location in memory. A union variable can contain only one of its members at
a time. The size of the union is at least the size of the largest member(大衛注:我想不出來大於的情況).

For related information, see class, struct, and Anonymous Union.

Declaring a Union

Begin the declaration of a union with the union keyword, and enclose the member list in curly braces:

union UNKNOWN    // Declare union type
{
   char   ch;
   int    i;
   long   l;
   float  f;
   double d;
}
 var1;          // Optional declaration of union variable
Using a Union

A C++ union is a limited form of the class type. It can contain access specifiers (public, protected, private), member data,
and member functions, including constructors and destructors. It cannot contain virtual functions or static data members. It
cannot be used as a base class, nor can it have base classes. Default access of members in a union is public.

A C union type can contain only data members.

In C, you must use the union keyword to declare a union variable. In C++, the union keyword is unnecessary:

Example 1

union UNKNOWN var2;   // C declaration of a union variable
UNKNOWN var3;         // C++ declaration of a union variable
Example 2

A variable of a union type can hold one value of any type declared in the union. Use the member-selection operator (.) to access a member of a union:

var1.i = 6;           // Use variable as integer
var2.d = 5.327;       // Use variable as double

為了避免對上述文字有稍許的歪曲,我故意沒有翻譯它,但在此對其進行一些歸納:
1.union是一種特殊的struct/class,是一種可用於容納多種類型的類型,但與struct/class不同的是,所有的成員變數共用同一儲存空間(最大的那一個成員類型的大小),這使得它具有多變的特性,可以在不同成員中任意切換,而無需藉助強制類型轉換,但這也使得你不能把它當作一個成員變數進行修改而不影響到另一成員變數;
2.union也可以有構造/解構函式,也可以包含訪問標識符,但不能包含虛函數或靜態成員變數/方法.

關於使用union時需要注意的一些問題,可以參考我的前一篇文章:<(大衛的閱讀筆記)C++中使用union的幾點思考>.
下面談談一些比較有意思並且有意義的union的應用.
1.in_addr

struct in_addr {
  union {
          struct { u_char s_b1,s_b2,s_b3,s_b4; }   S_un_b;
          struct { u_short s_w1,s_w2; }            S_un_w;
          u_long                                   S_addr;
  }
 S_un;
};

對於上面的struct,寫過socket應用的人,肯定都用過它.不知你注意過沒有,它包含了一個很有趣的union,該union的各成員具有相同的大小,分別代表同一資訊的不同表現形式.你在進行程式設計的時候也可以利用這一特性來提供同一資訊的不同表現形式,不過要注意,在進行跨平台應用時,位元組順序的影響可能給你造成一些不必要的麻煩.

2.匿名union
匿名union是沒有名稱和聲明列表的union,這跟'__unnamed' union不是一回事,它的聲明形式如下:
union { member-list } ;

匿名union僅僅通知編譯器它的成員變數共用一個地址,而變數本身是直接引用的,不使用通常的點號運算子文法.也正因此,匿名union與同一程式塊內的其它變數具有相同的範圍層級,需注意命名衝突.
請看下面的例子:

#include <iostream.h>

struct DataForm
{

    enum DataType { CharData = 1, IntData, StringData };
    DataType type;

    // Declare an anonymous union.
    union
    {

        char  chCharMem;
        char *szStrMem;
        int   iIntMem;
    };

    void print();
};

void DataForm::print()
{

    // Based on the type of the data, print the
    // appropriate data type.
    switch( type )
    {

    case CharData:
        cout << chCharMem;
        break;
    case IntData:
        cout << szStrMem;
        break;
    case StringData:
        cout << iIntMem;
        break;
    }
}

此外,匿名union還具有以下約束:
1).因為匿名聯合不使用點運算子,所以包含在匿名聯合內的元素必須是資料,不允許有成員函數,也不能包含私人或受保護的成員;
2).全域匿名聯合必須是靜態(static)的,否則就必須放在匿名名字空間中.

附註:
對匿名union的概念,你或許有些陌生,但對於Windows應用的開發人員,有一個經常用到的結構中就包含了匿名union,它就是VARIANT,也許你沒有注意它罷了:

typedef struct FARSTRUCT tagVARIANT VARIANT;
typedef struct FARSTRUCT tagVARIANT VARIANTARG;

typedef struct tagVARIANT  {
   VARTYPE vt;
   unsigned short wReserved1;
   unsigned short wReserved2;
   unsigned short wReserved3;
   union {
      Byte                    bVal;                 // VT_UI1.
      Short                   iVal;                 // VT_I2.
      long                    lVal;                 // VT_I4.
      float                   fltVal;               // VT_R4.
      // ...
   };
};

3.利用union進行類型轉換
前面已經說過,union具有多變的特性,可以在不同成員中任意切換,而無需藉助強制類型轉換,下面舉例說明這一點(其實1已經很好地說明了這一點):

#include <iostream>
using namespace std;

struct DATA
{

    char c1;
    char c2;
};

int main()
{

    union { 
        int i; 
        DATA data
    }
 _ut;
    
    _ut.i = 0x6162;

    cout << "_ut.data.c1 = " << _ut.data.c1 << endl
        <<
 "_ut.data.c2 = " << _ut.data.c2 << endl;
    
    return 0;
}

需要提醒你的是,資料類型的轉換,並非union的專長,只是一個可資利用的特性而已.因為,採用union進行類型間轉換極易受平台影響,如上面的程式採用Intel x86 + Windows 2000 + VC6時輸出為:
_ut.data.c1 = b
_ut.data.c2 = a
(
:因為Intel CPU的架構是Little Endian)
而在Sun的Sparc上,你得到的結果卻是:
_ut.data.c1 = 
_ut.data.c2 = 
(
:因為採用Big Endian時,前兩個位元組為0x0000)

而即便是在同一平台上,在integer類型與real類型間進行轉換時也不要採用union,否則,你會得到令你莫名其妙的結論(這是由於CPU對real類型的處理方式引起的,該方式在各平台上有極大區別,同時,根據C++ Standard,這種作法會引起"undefined behavior").

關於利用引用進行類型轉換,可參考<引用在強制類型轉化中的應用>.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.