C/C++联合(Union)浅谈

来源:互联网 发布:手机如何撤销淘宝投诉 编辑:程序博客网 时间:2024/05/29 07:26

原文:http://blog.csdn.net/masefee/article/details/4160211

联合提供了一种方式,能够规避C的类型系统,允许以多种类型来引用一个对象。联合声明的语法和结构体的语法一样,只不过语义相差很大。它们不是用不同的域来引用不同的存储器块,而是引用同一块存储块。


下面我们来举几个例子:

  1. struct STest
  2. {
  3.     char c;
  4.     int i[ 2];
  5.     double var;
  6. };


  7. union UTest
  8. {
  9.     char c;
  10.     int i[ 2];
  11.     double var;
  12. };


我们可以查看内存里面的分布:

类型 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的数据值,而每个内部节点都有指向孩子节点的指针,但是没有数据(因为是叶子节点)。如果我们像这样声明:

  1. struct NODE
  2. {
  3.     struct NODE* pLeft;
  4.     struct NODE* pRight;
  5.     double data;
  6. };



我们可以知道这样一个结构体需要16个字节,每个叶子节点都会浪费一半的字节。相反,如果我们用联合来声明一个节点:

  1. union NODE
  2. {
  3.     struct
  4.     {
  5.         union NODE* pLeft;
  6.         union NODE* pRight;
  7.     }inter;
  8.     double data;
  9. };


这样一来,每个节点就只需要8个字节。如果pNode是一个指向union NODE类型的指针,我们用pNode->data来引用叶子节点的数据。而pNode->inter.pLeft和pNode->inter.pRight来引用内部节点的孩子。

这样可能出现一种情况,就是无法确定是哪种节点(内部节点或叶子节点)。我们可以引用一个标志域。

  1. struct NODE
  2. {
  3.     BOOL isLeaf;
  4.     union
  5.     {
  6.         struct
  7.         {
  8.             union NODE* pLeft;
  9.             union NODE* pRight;
  10.         }inter;
  11.         double data;
  12.     }info;
  13. }

不过对于这样小的节省而导致代码的可读性变得差了一些。在这里联合带来的好处可以忽略。对于较多域的数据结构,这样的节省会更加吸引人一些。


还有一个用法就是用来访问不同数据类型的位。如:

  1. UINT floatToBits( float fVar)
  2. {
  3.     union
  4.     {
  5.         float fV;
  6.         UINT uI;
  7.     }temp;
  8.     temp.fV = fVar;
  9.     return temp.uI;
  10. }

我们看看汇编代码:

  1. mov eax,dword ptr [ fVar ]
  2. mov dword ptr [ temp ],eax


它跟下面的函数产生回汇编代码是一样的:

  1. UINT floatToBits( UINT var)
  2. {
  3.     return var;
  4. }


这就证明汇编代码里面缺乏信息,无论是什么类型都相对于EBP偏移固定的值。过程只是简单的拷贝,并没有修改任何位。


再举个例子吧:

  1. double bitToDouble( UINT uParam1, UINT uParam2)
  2. {
  3.     union
  4.     {
  5.         double d;
  6.         UINT u[ 2 ];
  7.     }temp;
  8.     temp.u[ 0] = uParam1;
  9.     temp.u[ 1] = uParam2;
  10.     return temp.d;
  11. }


好了,更多的用法大家在慢慢体会吧,这里就抛砖引玉了- - 



0 0