zoukankan      html  css  js  c++  java
  • C/C++联合(Union)浅谈

    原文: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. }


    好了,更多的用法大家在慢慢体会吧,这里就抛砖引玉了- -
    阅读(225) | 评论(2) | 转发(1) |
    给主人留下些什么吧!~~

    escarp2012-06-20 15:40:57

    Larpenteur: 多谢分享啊~.....

    Larpenteur2012-06-20 05:42:23

    多谢分享啊~

    评论热议
  • 相关阅读:
    Qtcreator中printf()/fprintf()不显示问题处理方法
    C++实现斐波那契数列
    DAPP超详细解释
    自底向上的合并排序算法
    Python 生成哈希hash--hashlib模块
    使用js的一些小技巧
    js——事件
    django学习
    js——js特效
    js--DOM学习
  • 原文地址:https://www.cnblogs.com/black/p/5171754.html
Copyright © 2011-2022 走看看