联合体(Union)

联合体(Union)简介

联合体(union)是 C 和 C++ 编程语言中的一种数据结构,和结构体(struct)类似,但有一些重要的区别。

定义
  • 联合体中的所有成员共享同一段内存 ,也就是说,联合体中的多个成员变量会占用相同的地址,但是在任何一个时间点只能存储一个成员的值。

1. 联合体的定义和语法

定义语法
c 复制代码
union UnionName {
    DataType member1;
    DataType member2;
    ...
};
示例
c 复制代码
union Example {
    int i;       // 整数,占用 4 字节
    float f;     // 浮点数,占用 4 字节
    char c;      // 字符,占用 1 字节
};
  • 这里的联合体 Example 包含了 3 个成员:
    • 一个整数 i,占用 4 字节。
    • 一个浮点数 f,占用 4 字节。
    • 一个字符 c,占用 1 字节。
  • 存储特点
    • 联合体的总大小 取决于它的最大成员 所需的内存大小(这里是 4 字节,因为 intfloat 都占 4 字节)。

2. 联合体的内存分配

内存共享特点
  • 联合体中的所有成员都共享同一块内存 ,因此:
    • 写入一个成员会覆盖其他成员的值。
    • 在任意时刻,联合体中只能存储一个有效值。
示例
c 复制代码
union Example {
    int i;       // 整数,占用 4 字节
    float f;     // 浮点数,占用 4 字节
    char c[4];   // 字符数组,占用 4 字节
};
union Example ex;
ex.i = 42;      // 写入整数 42
printf("i: %d\n", ex.i);    // 输出 i 的值:42
ex.f = 3.14;    // 写入浮点数 3.14
printf("f: %.2f\n", ex.f);  // 输出 f 的值:3.14
printf("i: %d\n", ex.i);    // 输出 i 的值:此时 i 的值已被覆盖
输出
i: 42
f: 3.14
i: 1078523331   // i 的值被 f 的写入覆盖,解释为浮点数的二进制形式

3. 联合体的用途

3.1 内存节省
  • 联合体非常适合需要节省内存的场景。
  • 由于多个成员共享同一段内存,可以显著减少内存占用。
3.2 数据转换
  • 联合体常用于类型转换,允许以不同的方式访问同一块数据。
示例:浮点数与二进制表示的转换
c 复制代码
#include <stdio.h>
union FloatToBits {
    float f;
    unsigned int bits;
};
int main() {
    union FloatToBits data;
    data.f = 3.14;   // 写入浮点数
    printf("Float: %.2f\n", data.f);          // 输出浮点数
    printf("Bits: 0x%X\n", data.bits);        // 输出二进制表示
    return 0;
}
输出
Float: 3.14
Bits: 0x4048F5C3
  • 同一块内存可以通过 data.f 访问为浮点数,通过 data.bits 访问为其二进制位。

4. 联合体的常见用途

4.1 数据协议处理
  • 联合体常用于解析二进制数据流。例如,在通讯协议中,可以通过联合体将字节流解析为特定的数据结构。
示例:解析 16 位数据的高低字节
c 复制代码
union Data16 {
    unsigned short full;  // 16 位数据
    struct {
        unsigned char low;  // 低字节
        unsigned char high; // 高字节
    } parts;
};
int main() {
    union Data16 data;
    data.full = 0x1234; // 写入 16 位数据
    printf("Full: 0x%X\n", data.full);      // 输出完整值
    printf("High: 0x%X\n", data.parts.high); // 输出高字节
    printf("Low: 0x%X\n", data.parts.low);   // 输出低字节
    return 0;
}
输出
Full: 0x1234
High: 0x12
Low: 0x34
应用场景
  • 网络协议
    • 在网络通讯中,经常需要解析协议头部,例如 IP 包头、TCP 包头等,联合体可以方便地拆解字段。
  • 嵌入式开发
    • 在嵌入式系统中,用联合体将字节序列解析为多字节变量(如 intfloat)。

4.2 硬件寄存器操作
  • 联合体可以用于操作硬件寄存器,通过联合体直接访问寄存器的特定位。
示例:32 位寄存器的分段访问
c 复制代码
union Register {
    unsigned int value;  // 寄存器的完整值
    struct {
        unsigned char byte0;  // 第 0 字节
        unsigned char byte1;  // 第 1 字节
        unsigned char byte2;  // 第 2 字节
        unsigned char byte3;  // 第 3 字节
    } bytes;
};
int main() {
    union Register reg;
    reg.value = 0x12345678; // 写入寄存器值
    printf("Byte 0: 0x%X\n", reg.bytes.byte0); // 输出低字节
    printf("Byte 1: 0x%X\n", reg.bytes.byte1); // 输出次低字节
    printf("Byte 2: 0x%X\n", reg.bytes.byte2); // 输出次高字节
    printf("Byte 3: 0x%X\n", reg.bytes.byte3); // 输出高字节
    return 0;
}
输出
Byte 0: 0x78
Byte 1: 0x56
Byte 2: 0x34
Byte 3: 0x12

5. 联合体与结构体的区别

特性 联合体(union) 结构体(struct)
内存分配 所有成员共享同一段内存,大小由最大成员决定 每个成员都有独立的内存,大小是所有成员内存之和
成员访问 同一时刻只能存储一个成员,访问其他成员可能导致数据不一致 所有成员可以同时访问,互不干扰
用途 内存节省,数据转换,多种数据形式的联合表示 表示多种属性的组合体
使用限制 不适合需要同时使用多个成员的场景 可以同时访问多个成员

6. 注意事项

  1. 数据覆盖
    • 由于所有成员共享内存,当你写入一个成员时,会覆盖其他成员的值。
    • 使用联合体时要非常小心,确保对成员的访问逻辑正确。
  2. 对齐与大小
    • 联合体的大小由其最大成员的大小决定,并可能受到编译器对齐(padding)的影响。
  3. 联合体与类型安全
    • 联合体没有类型检查机制,读写不同类型的成员时可能导致不安全行为。

7. 总结

  • 联合体是 C/C++ 中的一种高级数据类型,适用于节省内存、数据解析和类型转换等场景。
  • 其核心特点是成员共享同一段内存,这既带来了灵活性,也对程序员提出了更高的使用要求。
  • 常见用途包括:
    1. 数据协议解析(如解析高低字节)。
    2. 硬件寄存器操作
    3. 浮点数与二进制位的转换
    4. 节省内存空间的场景

如有侵权,联系删除

相关推荐
顽疲11 分钟前
java 小红书源码 1:1还原 uniapp
java·开发语言·uni-app
程序员 小柴21 分钟前
会话_JSP_过滤器_监听器_Ajax
java·开发语言·ajax
Yoyo25年秋招冲冲冲22 分钟前
【Java回顾】Day7 Java IO|分类(传输方式,数据操作)|零拷贝和NIO
java·开发语言·nio
I"ll carry you26 分钟前
【C++基础】enum,union,uint8_t,static
java·数据库·c++
Zfox_29 分钟前
【Linux】应用层自定义协议与序列化
linux·服务器·c语言·c++
杰克崔30 分钟前
通过内核模块按fd强制tcp的quickack方法
linux·运维·服务器·网络·tcp/ip
柯南二号1 小时前
【Kotlin】上手学习之类型篇
开发语言·学习·kotlin
Hacker_Nightrain1 小时前
内网渗透测试工具及渗透测试安全审计方法总结
网络·测试工具·安全
*TQK*1 小时前
C++/C语言判断重复数组(zznu)⭐
c语言·数据结构·c++
网络空间站1 小时前
T-SQL语言的学习路线
开发语言·后端·golang