4、状态命名规范:状态枚举命名、状态宏定义命名、状态变量命名

状态机写得好不好,看命名就知道。

我见过太多项目,状态名起得随心所欲。有的叫 STATE_1,有的叫 S_IDLE,还有的直接用数字 0、1、2 硬编码。说实话,这种代码三个月后连自己都看不懂。

命名这件事,说白了就是给状态机里的每个状态贴个清晰的标签。标签贴对了,代码可读性直接翻倍。今天我就把这几类命名的规范给你捋清楚。

核心原则:状态命名要做到「见名知意」。看到名字,不用查文档就知道这个状态是干什么的。

4.1 状态枚举命名

我个人习惯用枚举来定义状态集合。枚举的好处是编译器会帮你做类型检查,不容易写错。

命名格式:

  • 枚举类型名:状态机名_State_t,比如 Fsm_State_t
  • 枚举成员名:状态机名_STATE_状态名,比如 FSM_STATE_IDLE
// 好的命名
typedef enum {
    FSM_STATE_IDLE,
    FSM_STATE_INIT,
    FSM_STATE_RUNNING,
    FSM_STATE_ERROR,
    FSM_STATE_SLEEP
} Fsm_State_t;

// 差的命名
typedef enum {
    S0,    // 这是啥?
    S1,
    S2,
    S3,
    S4
} State_t;

你想想看,FSM_STATE_RUNNING 和 S2 哪个更容易理解?答案不言而喻。

小技巧:枚举值建议从 0 开始递增,不要手动赋值。除非你有特殊需求,比如要和硬件寄存器对齐。

4.2 状态宏定义命名

有些团队喜欢用宏定义来声明状态。虽然我个人更推荐枚举,但宏定义在某些场景下也有它的优势——比如在 C 语言的老旧项目中,或者需要和预处理逻辑配合时。

命名格式:

  • 宏名:状态机名_STATE_状态名,全部大写,下划线分隔
  • 值:使用十六进制或十进制,建议从 0x00 开始
// 宏定义命名规范
#define FSM_STATE_IDLE      0x00
#define FSM_STATE_INIT      0x01
#define FSM_STATE_RUNNING   0x02
#define FSM_STATE_ERROR     0x03
#define FSM_STATE_SLEEP     0x04

// 不推荐的做法
#define IDLE    0
#define INIT    1
#define RUN     2
#define ERR     3
#define SLEEP   4

我曾经在一个项目中看到有人用 #define ST_IDLE 0,结果全局搜索 ST 出来一大堆无关结果。加个前缀 FSM_STATE_ 就能避免这种尴尬。

注意:宏定义没有类型检查。如果你写错了状态值,编译器不会报错,运行时才会暴露问题。所以能用枚举就别用宏。

4.3 状态变量命名

状态变量是状态机的「心脏」。它记录着当前处于哪个状态。命名不好,整个状态机逻辑都会跟着乱。

命名格式:

  • 全局状态变量:g_状态机名_curState 或 g_状态机名_state
  • 局部状态变量:curState 或 state
  • 函数参数:newState 或 targetState
// 全局状态变量
static Fsm_State_t g_fsm_curState = FSM_STATE_IDLE;

// 局部状态变量
void fsm_process(void) {
    Fsm_State_t curState = g_fsm_curState;
    // ...
}

// 函数参数
void fsm_set_state(Fsm_State_t newState) {
    g_fsm_curState = newState;
}

这里有个坑:我见过有人把状态变量命名为 status。结果代码里既有 status 表示状态机状态,又有 status 表示错误码,两个混在一起,调试的时候差点崩溃。

避坑指南:我曾经在一个多状态机项目中,把两个状态机的状态变量都命名为 state。结果代码里到处是 state = XXX,根本分不清是哪个状态机。后来我强制要求:每个状态变量必须带上状态机名前缀。

4.4 命名规范总结

命名类别 推荐格式 示例 不推荐
枚举类型 状态机名_State_t Fsm_State_t State_t
枚举成员 状态机名_STATE_状态名 FSM_STATE_RUNNING RUN
宏定义 状态机名_STATE_状态名 FSM_STATE_IDLE ST_IDLE
全局变量 g_状态机名_curState g_fsm_curState state
局部变量 curState curState s

嗯,这张表你直接拿去用。团队规范里照着写就行。

4.5 命名规范流程图

下面这张图展示了状态命名的整体逻辑。从状态机名出发,衍生出枚举、宏、变量三类命名。每一类都有固定的模板。

状态命名规范结构图 状态机名 (Fsm) 枚举命名 Fsm_State_t FSM_STATE_IDLE 宏定义命名 #define FSM_STATE_IDLE 0x00 变量命名 g_fsm_curState curState (局部) 统一前缀 + 状态机名 + STATE + 状态名 例:FSM_STATE_RUNNING、g_fsm_curState

从这张图可以看出来,所有命名都围绕「状态机名」展开。只要确定了状态机名,枚举、宏、变量都能按模板生成。这就是规范的力量。

我的建议:团队里统一用一套命名模板。新人来了不用问,看一眼代码就知道状态名叫什么。这才是可读性的终极目标。

好了,命名规范就讲到这里。记住:好的命名是代码的说明书,差的命名是代码的迷魂汤。你自己选吧。

可可精品资料库