C 语言状态机实践
更新时间:2026-08-26。本文是
languages/c/主题高手层的骨架文档(占位),完整展开将在后续批次补齐。
本文要回答的问题
- 状态机解决什么问题?什么时候该用?
- 用
switch写状态机为什么容易写成长毛怪? - 状态转移表是什么?它凭什么更优雅?
一、状态机模型
状态机 = 状态 × 事件 → 新状态(+动作)。核心是把"一堆 if/else 纠缠的逻辑"显式拆成状态和转移:
c
typedef enum { S_IDLE, S_RUN, S_ERR } State;| 应用 | 状态 | 事件 |
|---|---|---|
| 协议解析 | 等待头/读长度/读载荷 | 字节到达 |
| 输入校验 | 起始/数字/小数/结束 | 字符类型 |
| 网络连接 | 监听/握手/就绪/关闭 | 报文 |
二、两种实现
| 方式 | 结构 | 优点 | 缺点 |
|---|---|---|---|
| switch 嵌套 | switch(state){ case ...: switch(event) | 直观、好读 | 状态×事件多了像毛线球 |
| 转移表 | 二维表:state × event → (next_state, handler) | 数据驱动、易扩展 | 要先设计表 |
转移表本质是 函数指针数组:
c
typedef struct { State next; void (*action)(void *ctx); } Trans;
static Trans table[ST_MAX][EV_MAX];主循环变成查表调用,新增状态/事件只需改表,不用动逻辑。
三、使用要点
- 状态要穷举、事件要穷举:查表得先确定越界处理。
- 动作(副作用)与状态跳转分离:先执行 action 再转移。
- 用 enum 代替裸整数,可读性大增,见 枚举。
四、与入门层的衔接
- 枚举与状态常量,见 枚举类型。
- switch 语法与陷阱,见 switch-case。
- 转移表与函数指针,见 函数指针进阶。
一句话总结
状态机把纠缠的条件逻辑变成"状态×事件"的显式表格:小状态机用 switch 够用,状态一多就上转移表,让新增分支变成改表而不是改逻辑。
本文为骨架文档:核心结构已就位,示例代码与实测数据将在后续批次补齐。