C/C++聯合(Union)淺談 .

來源:互聯網
上載者:User

聯合提供了一種方式,能夠規避C的類型系統,允許以多種類型來引用一個對象。聯合聲明的文法和結構體的文法一樣,只不過語義相差很大。它們不是用不同的域來引用不同的儲存空間塊,而是引用同一Block Storage塊。

下面我們來舉幾個例子:

struct STest

{

       char   c;

       int    i[ 2 ];

       double var;

};

 

union UTest

{

       char   c;

       int    i[ 2 ];

       double var;

};

 

我們可以查看記憶體裡面的分布:

類型         c     i    var    大小        

STest     0     4    12     20

UTest     0     0    0      8

上面的資料表示距離首地址的儲存空間塊位移。假如我們定義了UTest* pU; 我們分別察看p->c;  p->i[ 0 ];  p->var; 它們所引用的都是資料結構的起始位置。當然求sizeof的話。UTest的大小將是它的最大類型的資料成員的大小。

 

聯合的用處很多,這裡舉一個怎麼用它來節省空間的:

假設我們有一個二叉樹的資料結構,每個葉子節點都有一個double的資料值,而每個內部節點都有指向孩子節點的指標,但是沒有資料(因為是葉子節點)。如果我們像這樣聲明:

struct NODE

{

       struct NODE* pLeft;

       struct NODE* pRight;

       double       data;

};

我們可以知道這樣一個結構體需要16個位元組,每個葉子節點都會浪費一半的位元組。相反,如果我們用聯合來聲明一個節點:

union NODE

{

       struct

       {

              union NODE* pLeft;

              union NODE* pRight;

       }inter;

       double data;

};

這樣一來,每個節點就只需要8個位元組。如果pNode是一個指向union NODE類型的指標,我們用pNode->data來引用葉子節點的資料。而pNode->inter.pLeft和pNode->inter.pRight來引用內部節點的孩子。

這樣可能出現一種情況,就是無法確定是哪種節點(內部節點或葉子節點)。我們可以引用一個標誌域。

struct NODE

{

       BOOL  isLeaf;

       union

       {

              struct

              {

                     union NODE* pLeft;

                     union NODE* pRight;

              }inter;

              double data;

       }info;

}

 

不過對於這樣小的節省而導致代碼的可讀性變得差了一些。在這裡聯合帶來的好處可以忽略。對於較多域的資料結構,這樣的節省會更加吸引人一些。

 

還有一個用法就是用來訪問不同資料類型的位。如:

UINT floatToBits( float fVar )

{

       union

       {

               float  fV;

               UINT uI;

       }temp;

       temp.fV = fVar;

       return temp.uI;

}

我們看看彙編代碼:

mov         eax,dword ptr [ fVar ]

mov         dword ptr [ temp ],eax

 

它跟下面的函數產生回彙編代碼是一樣的:

UINT floatToBits( UINT var )

{

       return var;

}

這就證明彙編代碼裡面缺乏資訊,無論是什麼類型都相對於EBP位移固定的值。過程只是簡單的拷貝,並沒有修改任何位。

 

再舉個例子吧:

double bitToDouble( UINT uParam1, UINT uParam2 )

{

       union

       {

               double d;

               UINT u[ 2 ];  

       }temp;

       temp.u[ 0 ] = uParam1;

       temp.u[ 1 ] = uParam2;

       return temp.d;

}

 

好了,更多的用法大家在慢慢體會吧,這裡就拋磚引玉了- -

聯合提供了一種方式,能夠規避C的類型系統,允許以多種類型來引用一個對象。聯合聲明的文法和結構體的文法一樣,只不過語義相差很大。它們不是用不同的域來引用不同的儲存空間塊,而是引用同一Block Storage塊。

下面我們來舉幾個例子:

struct STest

{

       char   c;

       int    i[ 2 ];

       double var;

};

 

union UTest

{

       char   c;

       int    i[ 2 ];

       double var;

};

 

我們可以查看記憶體裡面的分布:

類型         c     i    var    大小        

STest     0     4    12     20

UTest     0     0    0      8

上面的資料表示距離首地址的儲存空間塊位移。假如我們定義了UTest* pU; 我們分別察看p->c;  p->i[ 0 ];  p->var; 它們所引用的都是資料結構的起始位置。當然求sizeof的話。UTest的大小將是它的最大類型的資料成員的大小。

 

聯合的用處很多,這裡舉一個怎麼用它來節省空間的:

假設我們有一個二叉樹的資料結構,每個葉子節點都有一個double的資料值,而每個內部節點都有指向孩子節點的指標,但是沒有資料(因為是葉子節點)。如果我們像這樣聲明:

struct NODE

{

       struct NODE* pLeft;

       struct NODE* pRight;

       double       data;

};

我們可以知道這樣一個結構體需要16個位元組,每個葉子節點都會浪費一半的位元組。相反,如果我們用聯合來聲明一個節點:

union NODE

{

       struct

       {

              union NODE* pLeft;

              union NODE* pRight;

       }inter;

       double data;

};

這樣一來,每個節點就只需要8個位元組。如果pNode是一個指向union NODE類型的指標,我們用pNode->data來引用葉子節點的資料。而pNode->inter.pLeft和pNode->inter.pRight來引用內部節點的孩子。

這樣可能出現一種情況,就是無法確定是哪種節點(內部節點或葉子節點)。我們可以引用一個標誌域。

struct NODE

{

       BOOL  isLeaf;

       union

       {

              struct

              {

                     union NODE* pLeft;

                     union NODE* pRight;

              }inter;

              double data;

       }info;

}

 

不過對於這樣小的節省而導致代碼的可讀性變得差了一些。在這裡聯合帶來的好處可以忽略。對於較多域的資料結構,這樣的節省會更加吸引人一些。

 

還有一個用法就是用來訪問不同資料類型的位。如:

UINT floatToBits( float fVar )

{

       union

       {

               float  fV;

               UINT uI;

       }temp;

       temp.fV = fVar;

       return temp.uI;

}

我們看看彙編代碼:

mov         eax,dword ptr [ fVar ]

mov         dword ptr [ temp ],eax

 

它跟下面的函數產生回彙編代碼是一樣的:

UINT floatToBits( UINT var )

{

       return var;

}

這就證明彙編代碼裡面缺乏資訊,無論是什麼類型都相對於EBP位移固定的值。過程只是簡單的拷貝,並沒有修改任何位。

 

再舉個例子吧:

double bitToDouble( UINT uParam1, UINT uParam2 )

{

       union

       {

               double d;

               UINT u[ 2 ];  

       }temp;

       temp.u[ 0 ] = uParam1;

       temp.u[ 1 ] = uParam2;

       return temp.d;

}

 

好了,更多的用法大家在慢慢體會吧,這裡就拋磚引玉了- -

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.