union关键字

来源:互联网 发布:java宿舍管理系统 编辑:程序博客网 时间:2024/05/17 06:38
1、union
   “联合”是一种特殊的类,也是一种构造类型的数据结构。在一个“联合”内可以定义多种不同的数据类型, 一个被说明为该“联合”类型的变量中,允许装入该“联合”所定义的任何一种数据,这些数据共享同一段内存,已达到节省空间的目的(还有一个节省空间的类型:位域)。 这是一个非常特殊的地方,也是联合的特征。另外,同struct一样,联合默认访问权限也是公有的,并且,也具有成员函数。
2、struct与union
   struct与union有一些相似之处。但两者有本质上的不同。在结构中各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和(空结构除外,同时不考虑边界调整)。而在“联合”中,各成员共享一段内存空间, 一个联合变量的长度等于各成员中最长的长度。应该说明的是, 这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。
3.使用注意事项
1)联合里面那些东西不能存放?
      我们知道,联合里面的东西共享内存,所以静态、引用都不能用,因为他们不可能共享内存。
2)类可以放入联合吗?
      我们先看一个例子:

class Test{      public:                Test():data(0) { }      private:          int data; };     typedef union _test     {             Test test;        }UI;   
     编译通不过,为什么呢?
     因为联合里不允许存放带有构造函数、析够函数、复制拷贝操作符等的类,因为他们共享内存,编译器无法保证这些对象不被破坏,也无法保证离开时调用析够函数。

3)又是匿名惹的祸??
       我们先看下一段代码: 

class test{        public:             test(const char* p);             test(int in);             const operator char*() const {return data.ch;}             operator long() const {return data.l;}        private:            enum type {Int, String };            union             {                  const char* ch;                  int i;             }datatype;            type stype;            test(test&);            test& operator=(const test&);};       test::test(const char *p):stype(String),datatype.ch(p){ }       test::test(int in):stype(Int),datatype.l(i)     {}

     看出什么问题了吗?呵呵,编译通不过。为什么呢?难道datatype.ch(p)和datatype.l(i)有问题吗?
     让我们来看看构造test对象时发生了什么,当创建test对象时,自然要调用其相应的构造函数,在构造函数中当然要调用其成员的构造函数,所以其要去调用datatype成员的构造函数,但是他没有构造函数可调用,所以出
错。
     注意了,这里可并不是匿名联合!因为它后面紧跟了个data! 

4)如何有效的防止访问出错?
    使用联合可以节省内存空间,但是也有一定的风险:通过一个不适当的数据成员获取当前对象的值!例如上面的ch、i交错访问。
    为了防止这样的错误,我们必须定义一个额外的对象,来跟踪当前被存储在联合中的值得类型,我们称这个额外的对象为:union的判别式。
     一个比较好的经验是,在处理作为类成员的union对象时,为所有union数据类型提供一组访问函数。
5)内存对齐问题.
暂不述.整理资料后,再发.

4.使用.

1.创建别名,在程序中经常会用到将一个数据类型强制转换为另一个类型,这个操作可以使用联合来代替。

比如

typedef union{char c;uint32 u;}CharOfUnion v;
可以通过v.u来操作一个uint32类型的对象,当需要将uint32变量的低端字节看做一个字符的时候,只需要访问v.c就可以了。

实际应用中,大多数的协议结构定义中,都会使用union类型来定义。

2、使用联合来将较大的对象分解成组成这个对象的各个字节。

typedef union{uint u;char bytes[4];}asBytes composite;
可以使用composite.bytes数组来访问composite.u字段的各个字节。

3.大端小端判别

大端:高字节数据在地址较小一端

小端:低字节数据在地址较小一端

BOOL  isBigEndian(){    int  i = 1;   /* i = 0x00000001*/    char  c = *(char  *)&i; /* 注意不能写成 char c = (char)i; */    return  (int )c != i;}
如果是little endian字节序的话,那个i = 1;的内存从小到大依次放的是:0x01 0x00 0x00 0x00,如是,按照i的起始地址变成按照char *方式(1字节)存取,即得c = 0x01;

甚至自己可以写大端小端转换函数

4)理解c++类的布局

有如下类:

class  Test{public :    float  getFVal(){ return  f;}private :    int  i;    char  c;    float  f;};Test t;
不能在类Test中增加代码,给对象中的f赋值7.0f.

方法:

class  Test_Cpy{ public :    float  getVal(){ return  f;}    float  setVal(float  f){ this ->f = f;}private :    int  i;    char  c;    float  f;};....int  main(){    Test t;    union    {         Test t1,          Test_Cpy t2;    }test;    test.t2.setVal(7.0f);    t = test.t1;    assert( t.getVal() == 7.0f );       return  0;}
说明:因为在增加类的成员函数时候,那个类的对象的布局基本不变。因此可以写一个与Test类一样结构的类Test_Cpy,而多了一个成员函数setVal,再用uinon结构对齐,就可以给私有变量赋值了。(这种方法在有虚机类和虚函数机制时可能失灵,故不可移植)至于详细的讨论,网上有,这个例子在实际中没有用途,只是用来考察这个内存布局的使用而已.
union在操作系统底层的代码中用的比较多,因为它在内存共赏布局上方便且直观。所以网络编程,协议分析,内核代码上有一些用到union都比较好懂,简化了设计。






整理自:

http://blog.csdn.net/feimor/article/details/6858103

http://blog.csdn.net/jiangnanyouzi/article/details/3158702

http://visionsky.blog.51cto.com/733317/151760


0 0