16 联合体与事件标签

核心:struct 分别存,union 共用存;type 决定当前数据按哪种事件解释。

1. 一张图看懂

flowchart TD
    E[Event 事件对象] --> T[type 事件标签]
    E --> U[union data 共用存储空间]
    T -->|1 按键事件| K[读取 data.key]
    T -->|2 断开事件| R[读取 data.reason]
    U -.保存当前事件的数据.-> K
    U -.保存当前事件的数据.-> R
structunion
内存成员分别占用存储空间成员共用一块存储空间
优点可以同时保存多个字段值节省内存,适合互斥的事件负载
限制可能需要更多空间及对齐填充不能依赖它同时保存多份独立数据

2. 标签 + 联合体:蓝牙事件示例

#include <stdint.h>

typedef struct {
    uint8_t type;          // 1=按键,2=断开
    union {
        uint8_t key;
        uint32_t reason;
    } data;
} Event;

Event e = {0};
e.type = 2;
e.data.reason = 7;

if (e.type == 2) {
    // 使用 e.data.reason:断开原因 7
}

必须让标签和写入的成员匹配:

写入方式是否符合约定
type=1 + data.key=3✅ 按键事件
type=2 + data.reason=7✅ 断开事件
type=1 + data.reason=7❌ 标签与负载不一致

type 是单独的字段,不是 union 自动维护的状态。写入其他成员也不会自动修改 type。

3. 工程记忆

  • union 的大小至少能容纳其最大的成员,也可能包含对齐填充;具体大小用 sizeof 验证。
  • 先判断 type,再访问对应的 data 成员,避免把数据解释成错误事件。
  • 多任务共享事件对象时,还需用第 14 节学过的同步方式保证标签和负载的一致性;union 不会自动保证线程安全。

一句话:type 是盒子的标签,union 是共用的盒子;标签必须和实际内容一致。