C中联合(union)用法

本文详细介绍了C/C++中联合(union)的概念、特点及使用方法。解释了联合与结构体的区别,展示了如何定义和使用联合,包括匿名联合的用法。并通过实例演示了联合在实际编程中的应用。
联合(union)在C/C++里面见得并不多,但是在一些对内存要求特别严格的地方,联合又是频繁出现,那么究竟什么是联合、怎么去用、有什么需要注意的地方呢?就这些问题,我试着做一些简单的回答,里面肯定还有不当的地方,欢迎指出! 
1、什么是联合?
   “联合”是一种特殊的类,也是一种构造类型的数据结构。在一个“联合”内可以定义多种不同的数据类型, 一个被说明为该“联合”类型的变量中,允许装入该“联合”所定义的任何一种数据,这些数据共享同一段内存,已达到节省空间的目的(还有一个节省空间的类型:位域)。 这是一个非常特殊的地方,也是联合的特征。另外,同struct一样,联合默认访问权限也是公有的,并且,也具有成员函数。
2、联合与结构的区别?
   “联合”与“结构”有一些相似之处。但两者有本质上的不同。在结构中各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和(空结构除外,同时不考虑边界调整)。而在“联合”中,各成员共享一段内存空间, 一个联合变量的长度等于各成员中最长的长度。应该说明的是, 这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。
   下面举一个例了来加对深联合的理解。 
    例4:
#include <stdio.h>
void main()
{
        union number
        {                   /*定义一个联合*/
                int i;
                struct
                {             /*在联合中定义一个结构*/
                        char first;
                        char second;
                }half;
        }num;
        num.i=0x4241;         /*联合成员赋值*/
        printf("%c%c\n", num.half.first, num.half.second);
        num.half.first='a';   /*联合中结构成员赋值*/
        num.half.second='b';
        printf("%x\n", num.i);
        getchar();
}
    输出结果为: 
     AB 
     6261 
    从上例结果可以看出: 当给i赋值后, 其低八位也就是first和second的值; 当给first和second赋字符后, 这两个字符的ASCII码也将作为i 的低八位和高八位。
3、如何定义?
   例如:
    union test
    {
      test() { }
      int office;
      char teacher[5];
    }; 
    定义了一个名为test的联合类型,它含有两个成员,一个为整型,成员名office;另一个为字符数组,数组名为teacher。联合定义之后,即可进行联合变量说明,被说明为test类型的变量,可以存放整型量office或存放字符数组teacher。
4、如何说明?
   联合变量的说明有三种形式:先定义再说明、定义同时说明和直接说明。
   以test类型为例,说明如下:
    1) union test
       {
         int office;
         char teacher[5];
       }; 
       union test a,b;    /*说明a,b为test类型*/
    2) union test
       {
         int office;
         char teacher[5];
       } a,b;
    3) union 
       {
         int office;
         char teacher[5];
       } a,b; 
       经说明后的a,b变量均为test类型。a,b变量的长度应等于test的成员中最长的长度,即等于teacher数组的长度,共5个字节。a,b变量如赋予整型值时,只使用了4个字节,而赋予字符数组时,可用5个字节。
5、如何使用?
   对联合变量的赋值,使用都只能是对变量的成员进行。联合变量的成员表示为:     
联合变量名.成员名 
例如,a被说明为test类型的变量之后,可使用a.class、a.office 
不允许只用联合变量名作赋值或其它操作,也不允许对联合变量作初始化赋值,赋值只能在程序中进行。
还要再强调说明的是,一个联合变量,每次只能赋予一个成员值。换句话说,一个联合变量的值就是联合变员的某一个成员值。
6、匿名联合
   匿名联合仅仅通知编译器它的成员变量共同享一个地址,而变量本身是直接引用的,不使用通常的点号运算符语法.例如:
     #i nclude <iostream>
     void main()
     {
         union{ 
                int test;
                char c; 
               };          
        test=5;
        c=′a′;
        std::cout<<i<<" "<<c;
     }
    正如所见到的,联合成分象声明的普通局部变量那样被引用,事实上对于程序而言,这也正是使用这些变量的方式.另外,尽管被定义在一个联合声明中,他们与同一个程序快那的任何其他局部变量具有相同的作用域级别.这意味这匿名联合内的成员的名称不能与同一个作用域内的其他一直标志符冲突.
    对匿名联合还存在如下限制:
    因为匿名联合不使用点运算符,所以包含在匿名联合内的元素必须是数据,不允许有成员函数,也不能包含私有或受保护的成员。还有,全局匿名联合必须是静态(static)的,否则就必须放在匿名名字空间中。
7、几点需要讨论的地方:
   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数据类型提供一组访问函数。
<think>嗯,用户问的是C语言中的union联合的功能和作用,我需要详细解释一下。首先,得从基础概念说起,union和struct有点像,但又有区别。应该先比较两者的不同,让用户更容易理解。 用户可能是刚开始学C语言,或者对内存管理不太熟悉,所以需要讲清楚union的内存分配方式。比如,union的成员共享同一块内存,这点和struct每个成员有独立内存不同。举例说明的时候,用简单的数据类型比较好,比如int和char,这样用户容易想象内存布局。 然后,union的主要作用是什么?节省内存空间,这在嵌入式系统或内存紧张的环境下很有用。比如,处理不同数据类型的同一块内存区域,或者做类型转换。可能需要举一个实际的例子,比如IP地址的存储,用union来同时支持IPv4和IPv6的不同表示方式。 还要提到使用union需要注意的地方,比如同时只能有一个成员有效,修改一个成员会影响其他成员的值。这些是常见的陷阱,用户需要特别注意的地方。 另外,union在系统编程中的应用,比如处理硬件寄存器或者协议解析,这时候union可以方便地访问同一内存的不同部分。例如,将一个32位的寄存器拆分成多个位段,用union和struct结合来实现。 可能用户还想知道union的大小计算,比如对齐的问题。最大成员的大小加上对齐调整,这部分需要简单说明,但不用太深入,避免让用户感到复杂。 有没有实际的代码示例?比如定义一个union,展示不同成员的赋值和读取结果的变化。比如用int和char数组,修改char数组会影响int的值,这样直观地展示内存共享的效果。 总结的时候,要强调union的优缺点,适用场景,以及使用时需要注意的问题。这样用户能全面了解何时使用union,避免误用。 需要确保用词准确,但不过于技术化,让初学者也能理解。可能用户没有接触过内存布局的概念,所以需要用简单易懂的语言解释。同时,保持回答结构清晰,分点说明,这样用户看起来有条理。 检查一下是否有错误,比如union的内存分配确实是所有成员共享最大成员的内存,对吗?是的。所以每个时间点只能使用一个成员,否则数据会被覆盖。这部分需要明确说明。 最后,确认是否覆盖了用户的问题,是否还有其他相关的内容需要补充,比如和typedef结合使用,或者union联合体中的高级用法,但可能对于介绍性质的问题,不需要太深入,保持基础即可。</think>C语言中的union联合)是一种特殊的数据类型,它的核心功能是**让多个成员共享同一块内存空间**。以下是逐步解析其功能和作用: --- ### 一、基础概念 - **定义方式**:与`struct`(结构体)类似,但成员共享内存。 ```c union Data { int i; float f; char str[20]; }; // 所有成员共享内存,大小为最大成员的大小(此处为20字节) ``` --- ### 二、核心特性 1. **内存共享** - union中所有成员的**起始地址相同**。 - 修改任意成员的值,其他成员的值可能被覆盖。 - 示例: ```c union Number { int a; char b; } num; num.a = 0x12345678; // 占用4字节 num.b = 0xFF; // 覆盖第一个字节(小端模式下) // 此时num.a的值被修改为0x123456FF ``` 2. **节省内存** - union的大小等于其**最大成员的大小**(需考虑内存对齐)。 - 适用于“同一时间只使用一个成员”的场景(如协议解析、类型转换)。 --- ### 三、典型应用场景 1. **类型转换** 无需指针操作,直接通过共享内存实现数据二进制层面的转换: ```c union Converter { float f; unsigned int u; } conv; conv.f = 3.14; printf("Float的二进制表示: 0x%X", conv.u); // 直接读取浮点的二进制形式 ``` 2. **协议解析** 处理不同格式的数据包(如同时支持IPv4和IPv6): ```c union IPAddress { uint32_t ipv4; // 4字节 uint8_t ipv6[16]; // 16字节 }; ``` 3. **硬件寄存器访问** 联合结构体访问寄存器的不同位段: ```c typedef union { struct { uint8_t bit0 : 1; uint8_t bit1 : 1; // ...其他位段 }; uint8_t reg; // 整体寄存器值 } StatusRegister; ``` --- ### 四、注意事项 1. **成员互斥性** 同一时间只能有效存储一个成员的值,修改成员会破坏其他成员数据。 2. **内存对齐影响** union的实际大小可能因内存对齐规则略大于最大成员(需用`#pragma pack`控制)。 3. **初始化问题** 只能初始化第一个成员: ```c union Data data = {10}; // 正确,初始化int i ``` --- ### 五、对比struct(结构体) | 特性 | union | struct | |--------------|--------------------|---------------------| | 内存分配 | 共享内存 | 成员内存独立 | | 大小 | 最大成员的大小 | 所有成员大小之和+对齐 | | 成员访问 | 互斥 | 可同时访问 | | 典型用途 | 节省内存、类型转换 | 数据聚合 | --- ### 六、总结 - **优点**:节省内存、灵活的类型转换能力。 - **缺点**:数据安全性低,需谨慎管理成员访问。 - **适用场景**:内存敏感型程序、硬件编程、协议处理等需要复用内存的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值