有限狀態機(Finite State Machine)將系統行為建模為有限個狀態、事件觸發、狀態轉移與動作執行的封閉系統。核心三元組:
事件 + 當前狀態 → 動作 + 下一狀態
廣泛應用於協議棧(TCP/PPP)、遊戲 AI、UI 流程、硬件控制器、詞法分析器等領域。
switch (cur_state) {
case S0:
if (e0) { act0(); /* 留在 S0 */ }
else if (e1) { act1(); next = S1; }
else if (e2) { act2(); next = S2; }
break;
case S1:
if (e2) { act2(); next = S2; }
break;
case S2:
if (e0) { act0(); next = S0; }
break;
}
cur_state = next;
優點:直觀、易寫、適合小型 FSM(<10 狀態)
缺點:隱含優先級(if-else 順序)、順序查找 O(n)、擴展性差、狀態/事件耦合
typedef struct { State next; void (*act)(void); } Trans;
Trans table[STATE_MAX][EVENT_MAX] = {
[S0][E0] = {S0, act0}, [S0][E1] = {S1, act1}, [S0][E2] = {S2, act2},
[S1][E2] = {S2, act2},
[S2][E0] = {S0, act0},
};
// 運行時
Trans t = table[cur_state][event];
if (t.act) t.act();
cur_state = t.next;
優點:O(1) 查找、數據與邏輯分離、易維護、支持動態修改表、可自動生成代碼
缺點:稀疏表浪費內存、動作函數簽名需統一、C 語言初始化語法繁瑣
void handle_E0(State *s) {
switch (*s) { case S0: case S2: act0(); *s = S0; break; }
}
void handle_E1(State *s) {
switch (*s) { case S0: act1(); *s = S1; break; }
}
void handle_E2(State *s) {
switch (*s) { case S0: case S1: act2(); *s = S2; break; }
}
// 事件到達時調用對應處理函數
優點:符合事件驅動架構、無隱含優先級、單一事件處理內聚、易於中斷/回調模型、TCP/PPP 實踐證明高效
缺點:狀態分散在多個函數,全局視圖需借圖表
typedef void (*StateFunc)(void);
StateFunc state_table[] = {state_S0, state_S1, state_S2};
// 每個狀態函數內部處理事件並設置全局 next_state
void state_S0() { if (e0) act0(); else if (e1) {act1(); next=S1;} ... }
void main() { while(1) state_table[cur_state](); cur_state = next_state; }
優點:面向對象風格、狀態邏輯封裝、易單元測試
缺點:間接調用開銷、需全局/上下文傳遞數據
enum {S0, S1, S2, S3, S4} state = S0;
while (1) {
char c = getchar();
switch (state) {
case S0: if (c=='2') state=S1; else state=S0; break;
case S1: if (c=='4') state=S2; else state=S0; break;
case S2: if (c=='7') state=S3; else state=S0; break;
case S3: if (c=='9') state=S4; else state=S0; break;
case S4: puts("Open!"); state=S0; break;
}
}
typedef struct { State cur; char in; State nxt; } Trans;
Trans trans[] = {{S0,'2',S1}, {S1,'4',S2}, {S2,'7',S3}, {S3,'9',S4}};
while ((c=getchar()) != 'q') {
for (int i=0; i<4; i++)
if (state==trans[i].cur && c==trans[i].in) { state=trans[i].nxt; break; }
if (state==S4) { puts("Open!"); state=S0; }
}
// 游戲主循環
enum {MENU, PLAYING, PAUSED, SETTINGS, EXIT} game_state = MENU;
while (game_state != EXIT) {
switch (game_state) {
case MENU: handle_menu(); break; // 內部含子狀態:START/OPT/QUIT
case PLAYING: update_game(); break;
case PAUSED: handle_pause(); break;
case SETTINGS: handle_settings(); break;
}
render();
}
子狀態機獨立封裝,如 handle_menu() 內部再用枚舉+switch 處理選項切換。
assert(valid_trans[cur][evt]) 捕獲非法路徑FsmCtx,支持多實例並發on_enter/on_exit 鉤子,處理資源申請釋放| 維度 | 硬件 (FPGA/ASIC) | 軟件 (C/RTOS) |
|---|---|---|
| 驅動方式 | 時鐘沿觸發(同步) | 事件/消息觸發(異步) |
| 並行性 | 真並行,組合邏輯 0 延遲 | 順序執行,需關注執行時間 |
| 編碼風格 | 垂直寫法(always @(posedge clk)) | 水平寫法更適合事件模型 |
| 狀態編碼 | One-hot/Gray/二進制優化面積時序 | 枚舉即可,編譯器優化 |
掌握 FSM 四大模式與選型原則,能將錯綜複雜的業務邏輯轉化為清晰、可驗證、可維護的代碼結構。記住:狀態機不是寫代碼的技巧,而是設計系統行為的思維框架。