跳转到内容

C++ 与 C 联合体

来自代码酷


C++与C联合体(Union)是一种特殊的数据结构,允许在相同的内存位置存储不同的数据类型。联合体在C和C++中广泛用于内存优化、硬件访问以及跨语言交互场景。本文将详细介绍联合体的语法、特性、应用场景及与C++类的区别。

联合体基础[编辑 | 编辑源代码]

联合体是一种用户定义的数据类型,与结构体(struct)类似,但所有成员共享同一块内存空间。这意味着同一时间只能存储一个成员的值,修改一个成员会影响其他成员的值。

语法定义[编辑 | 编辑源代码]

联合体使用union关键字定义:

union MyUnion {
    int intValue;
    float floatValue;
    char charValue;
};

内存布局[编辑 | 编辑源代码]

联合体的所有成员从同一内存地址开始,其大小为最大成员的大小。例如:

pie title 联合体内存分配 "intValue (4字节)" : 4 "floatValue (4字节)" : 4 "charValue (1字节)" : 1

C++中的联合体扩展[编辑 | 编辑源代码]

C++11起,联合体支持更多特性:

  • 可包含非POD(Plain Old Data)类型(如带有构造函数的类)
  • 可定义成员函数(包括构造函数/析构函数)
  • 支持访问控制(public/protected/private)

示例:

union AdvancedUnion {
    std::string str;  // C++11起支持
    int num;
    ~AdvancedUnion() {} // 需手动管理非POD成员
};

与C交互的注意事项[编辑 | 编辑源代码]

当C++联合体需要与C代码交互时需注意: 1. 只使用POD类型成员 2. 避免使用C++特有的特性(如成员函数) 3. 使用extern "C"声明

代码示例[编辑 | 编辑源代码]

基础用法[编辑 | 编辑源代码]

#include <iostream>
union Data {
    int i;
    float f;
    char c;
};

int main() {
    Data data;
    data.i = 42;
    std::cout << "Integer: " << data.i << std::endl;
    
    data.f = 3.14f;
    std::cout << "Float: " << data.f << std::endl;
    // 此时data.i的值已被覆盖
}

输出:

Integer: 42
Float: 3.14

类型双关(Type Punning)[编辑 | 编辑源代码]

联合体常用于类型转换:

union Converter {
    uint32_t i;
    float f;
};

float intToFloat(uint32_t x) {
    Converter c;
    c.i = x;
    return c.f;
}

实际应用场景[编辑 | 编辑源代码]

硬件寄存器访问[编辑 | 编辑源代码]

嵌入式系统中常用联合体访问硬件寄存器:

union GPIO_Register {
    uint32_t raw;
    struct {
        uint32_t mode : 2;
        uint32_t pull : 2;
        uint32_t reserved : 28;
    } bits;
};

协议解析[编辑 | 编辑源代码]

网络协议中解析多格式数据:

union Packet {
    uint8_t bytes[4];
    struct {
        uint16_t header;
        uint8_t command;
        uint8_t checksum;
    } fields;
};

联合体与结构体的对比[编辑 | 编辑源代码]

特性 联合体 结构体
内存使用 共享内存 独立内存
大小 最大成员大小 所有成员大小之和
同时访问 只能访问一个成员 可同时访问所有成员

数学表示[编辑 | 编辑源代码]

联合体的内存分配可表示为: sizeof(union)=max(sizeof(m1),sizeof(m2),...,sizeof(mn))

注意事项[编辑 | 编辑源代码]

  • 使用联合体时需明确知道当前存储的类型
  • 在C++中,包含非POD类型的联合体需要显式管理生命周期
  • 类型双关在某些编译器中可能导致未定义行为(可用std::memcpy作为替代)

进阶主题[编辑 | 编辑源代码]

匿名联合体[编辑 | 编辑源代码]

C++允许匿名联合体直接访问成员:

struct Variant {
    enum { INT, FLOAT } type;
    union {
        int i;
        float f;
    }; // 匿名联合体
};

带标签的联合体[编辑 | 编辑源代码]

通常结合枚举类型使用以实现类型安全:

struct TaggedUnion {
    enum Tag { INT, FLOAT } tag;
    union {
        int i;
        float f;
    };
    
    void set(int x) { i = x; tag = INT; }
    void set(float x) { f = x; tag = FLOAT; }
};

总结[编辑 | 编辑源代码]

联合体是C/C++中高效利用内存的重要工具,特别适合:

  • 需要节省内存的场景
  • 硬件寄存器访问
  • 协议数据解析
  • 类型转换操作

C++开发者应优先考虑使用std::variant(C++17)等更安全的替代方案,但在与C交互或需要极致性能时,联合体仍是重要选择。