C语言中Union的用法

本文详细解析了C/C++联合体的概念及应用,包括如何在多个基本数据类型或复合数据结构共享内存时使用联合体,以及在联合体内存放类、构造函数、析构函数等的限制。通过具体代码示例,阐述了联合体在内存分配和数据访问方面的特点,并提供了有效防止访问出错的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在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数据类型提供一组访问函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

king110108

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值