union联合体

一、概念

        共用体,也叫联合体,在一个“联合”内可以定义多种不同的数据类型, 一个被说明为该“联合”类型的变量中,允许装入该“联合”所定义的任何一种数据,这些数据共享同一段内存,以达到节省空间的目的。union变量所占用的内存长度等于最长的成员的内存长度。

二、内存占用和赋值问题   

     它是一个特殊的类,特殊在任意时刻,联合体内只能有一个数据成员可以有值,当给联合中某个成员赋值之后,该联合中的其他成员就变成未定义状态,值也等于当前被赋值的成员的值,没有了实际意义。举例说明:
   1、 例1:定义一个联合体如下:
union Token{
   char cval;
   int ival;
   double dval;
};
    以上代码定义了一个名为Token的联合,该联合中包含了3个数据成员。
Token token;
 
token.cval = 'a';
 
token.ival = 1;
 
token.dval = 2.5;
    在任意时刻,联合中只能有一个数据成员的值是有意义的。具体而言:以上代码定义了联合Token的一个变量token,此时token所占内存的数据如下图所示。
    
    红色方框内的数据即为token所占内存数据。因为token中长度最大的变量是double类型,所以token的长度是8个字节。

    之后首先为token的变量cval赋值,此时token所占内存的数据如下图所示。

    
        此时,token所占内存的第一个字节的值变为0x61,即字符’a’。

        接下来为token的变量ival赋值,此时token所占内存的数据如下图所示。

    
       此时,token所占内存的前四个字节变为0x00000001,即为数字1。在对tokenival赋值之后,cval的值就变为了0x01,实际上就没有意义了。
       最后,为token的变量dval赋值,此时token所占内存的数据如下图所示。
        
    此时,token所占内存的八个字节都有了相应的值。在对tokendval赋值之后,cval的值变为了0x00,而ivale的值变为了0x00000000,都没有了实际意义,也就是之前提到的未定义状态。

   2、 例2:写出下面程序的运算结果
        
int main()
{
    union EXAMPLE
	{
		struct 
		{
			int x, y;
		}in;
		int a, b;
	}e;

	e.a = 1;
	e.b = 2;
	e.in.x = e.a*e.b;
	e.in.y = e.a + e.b;
	printf("%d,%d\n", e.in.x, e.in.y);
	return 0;
        //输出为:4,8
}
        分析:
        在union中,所有的共用体成员共用一个空间,并且同一时间只能储存其中一个成员变量的值.
        e.a=1;
        e.b=2;
        //现在e只能存储一个成员变量的值e.b=e.a=2
        e.in.x=(e.a)*(e.b); //e里的in成员里的x成员=2*2=4
        //现在e只能存储一个成员变量的值e.b=e.a=4
        e.in.y=(e.a)+(e.b);//e里的in成员里的y成员=4+4=8

三、访问权限

        联合可以为其成员指定publicprotectedprivate等访问权限,默认情况下,其成员的访问权限为public

四、为成员指定长度
        联合的存储空间至少能够容纳其最大的数据成员。也可以为联合的成员指定长度。通过冒号操作符来实现成员长度的指定。   
union U {
 
unsigned short int aa;
 
struct {
 
unsigned int bb : 7;//(bit 0-6)
 
unsigned int cc : 6;//(bit 7-12)
 
unsigned int dd : 3;//(bit 13-15)
 
};
 
} u;
    以上代码定义了一个名为U的联合,并且定义了U的变量u。联合U包含两个成员,一个是unsigned short int类型的变量,其大小为2个字节;另一个是一个自定义结构,该自定义结构中包含了3unsigned int类型的变量。需要注意的是,每个unsigned int类型的变量的大小并不是默认的4个字节,而是通过冒号操作符指定了其大小,该大小的单位是比特。所以,联合u的大小是2个字节。之后,对联合u中的aa进行赋值:
u.aa = 0xE07F;

    此时,联合u所占的内存数据如下图所示。

    
    此时,u.bb所处的位置是0-6比特;u.cc所处的位置是7-12比特;u.dd所处的位置是13-15比特,如下图所示:
    
        所以,此时u.bb的值是127u.cc的值是0u.dd的值是7

四、测试大小端

        union的一个用法就是可以用来测试CPU是大端模式还是小端模式:
    
#include <iostream>
using namespace std;

void checkCPU()
{
    union MyUnion{
        int a;
        char c;
    }test;
    test.a = 1;
    if (test.c == 1)
        cout << "little endian" <<endl;
    else cout << "big endian" <<endl;
}

int main()
{
    checkCPU();
    return 0;
}

五、c++中的union
        上面总结的union使用法则,在C++中依然适用。如果加入对象呢?
#include <iostream>
using namespace std;

class CA
{
     int m_a;
};

union Test
{
     CA a;
     double d;
};

int main()
{
     return 0;
}
    
上面代码运行没有问题。如果在类CA中添加了构造函数,或者添加析构函数,就会发现程序会出现错误。由于union里面的东西共享内存,所以不能定义静态、引用类型的变量。由于在union里也不允许存放带有构造函数、析构函数和复制构造函数等的类的对象,但是可以存放对应的类对象指针。编译器无法保证类的构造函数和析构函数得到正确的调用,由此,就可能出现内存泄漏。所以,在C++中使用union时,尽量保持C语言中使用union的风格,尽量不要让union带有对象。


全部评论

相关推荐

Lorn的意义:你这标个前端是想找全栈吗?而且项目确实没什么含金量,技术栈太少了,边沉淀边找吧 现在学院本想就业好一点四年至少得高三模式两年加油吧
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务