您的位置:首页 > 编程语言 > C语言/C++

C语言中Union的用法

2016-04-02 12:01 169 查看
在C/C++程序的编写中,当多个基本数据类型或复合数据结构要占用同一片内存时,我们要使用联合体;当多种类型,多个对象,多个事物只取其一时(我们姑且通俗地称其为“n 选1”),我们也可以使用联合体来发挥其长处。

先看一段代码:

union myun
{
struct
{
int x;
int y;
int z;
}u;
int k;
}a;
int main()
{
a.u.x =4;
a.u.y =5;
a.u.z =6;
a.k = 0;
printf("%d %d %d\n",a.u.x,a.u.y,a.u.z);
return 0;
}
union类型是共享内存的,以size最大的结构作为自己的大小,这样的话,myun这个结构就包含u这个结构体,而大小也等于u这个结构体 的大小,在内存中的排列为声明的顺序x,y,z从低到高,然后赋值的时候,在内存中,就是x的位置放置4,y的位置放置5,z的位置放置6,现在对k赋 值,对k的赋值因为是union,要共享内存,所以从union的首地址开始放置,首地址开始的位置其实是x的位置,这样原来内存中x的位置就被k所赋的
值代替了,就变为0了,这个时候要进行打印,就直接看内存里就行了,x的位置也就是k的位置是0,而y,z的位置的值没有改变,所以应该是0,5,6.

如果我们把上面的代码再稍微改一下:

#include <stdio.h>

typedef union test
{
struct
{
int x;
int y;
int z;
}num;
int i;
int j;
}test1;

int main(int argc, char *argv[])
{
test1 temp;
temp.num.x = 4;
temp.num.y = 5;
temp.num.z = 6;
temp.i = 0;
temp.j = 1;
printf("x=%d,y=%d,z=%d,i=%d,j=%d\n",temp.num.x,temp.num.y,temp.num.z,temp.i,temp.j);

}
这个时候输出的是什么呢?其实结果是x=1,y=5,z=6,i=1,j=1。

我们看下内存模型

*------------------------------------------------------------------------------------------

* 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0| 0 0 0 0 0 0 0 0

* x=4 |
y=5 |
z=6 执行完结构体的初始化内存中的值

*------------------------------------------------------------------------------------------

* x=0,i=0
| y=5 |
z=6 执行完i=0后内存中的值

*------------------------------------------------------------------------------------------

* x=1,i=1,j=1 | y=5
| z=6
执行完j=1后内存中的值

*------------------------------------------------------------------------------------------

*/

使用Union时几点值得注意的地方

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数据类型提供一组访问函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: