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 -.保存当前事件的数据.-> Rstruct | union | |
|---|---|---|
| 内存 | 成员分别占用存储空间 | 成员共用一块存储空间 |
| 优点 | 可以同时保存多个字段值 | 节省内存,适合互斥的事件负载 |
| 限制 | 可能需要更多空间及对齐填充 | 不能依赖它同时保存多份独立数据 |
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 是共用的盒子;标签必须和实际内容一致。