狀态機的基本實作手段是
switch case
語句,不過也可以用函數指針來實作。舉例說明,這裡有個
switch case
實作的狀态機。
switch case 實作的狀态機
int count = 0;
typedef enum {
STATE1,
STATE2,
STATE3,
}state_t;
state_t state = STATE1;
void state_machine(void) {
switch(state) {
case STATE1:
if(count > 3) {
state = STATE2;
}
break;
case STATE2:
if(count > 10) {
state = STATE3;
}
break;
case STATE3:
if(count > 100) {
state = STATE1;
}
break;
default:
break;
}
}
int main(void) {
for(;count < 200; count++) {
state_machine();
}
return 0;
}
函數指針實作的狀态機
int count = 0;
typedef void (*state_t)(void);
void STATE1(void);
void STATE2(void);
void STATE3(void);
state_t state = STATE1;
void STATE1(void) {
if(count > 3) {
state = STATE2;
}
}
void STATE2(void) {
if(count > 10) {
state = STATE3;
}
}
void STATE3(void) {
if(count > 100) {
state = STATE1;
}
}
int main(void) {
for(;count < 200; count++) {
state();
}
return 0;
}
改動内容包括:
- 狀态枚舉的定義變更為狀态處理函數指針的定義。
- 每一個
語句分離成為狀态處理函數。case
- 調用狀态機的地方直接調用狀态處理函數指針。
函數指針實作狀态機的好處:
- 進入狀态處理的時間是固定的,無論有幾個狀态。使用
實作時,switch case
預設情況下與 switch case
語句生成的代碼一緻,要依次進行判斷,進入後面狀态處理的時間要比進入前面狀态處理的時間要長。if else
- 每個狀态一個函數,函數的塊頭比較小,特别是狀态處理的内容比較多的時候,分離成函數比較好閱讀。
函數指針實作狀态機的壞處:
- 如果狀态處理的内容很少,而狀态很多,那麼會分離成好多很小的函數。
更多内容
處理進入、退出狀态
#include <stddef.h>
int count;
typedef enum {
EV_DO,
EV_ENTER,
EV_EXIT,
}event_t;
typedef void (*state_t)(event_t e);
void trans(state_t next);
void STATE1(event_t e);
void STATE2(event_t e);
void STATE3(event_t e);
state_t state = NULL;
void STATE1(event_t e)
{
switch(e) {
case EV_DO:
if(count > 3) {
trans(STATE2);
}
break;
case EV_ENTER:
count = 0;
break;
default:
break;
}
}
void STATE2(event_t e)
{
switch(e) {
case EV_DO:
if(count > 10) {
trans(STATE3);
}
break;
case EV_EXIT:
count = 1;
break;
default:
break;
}
}
void STATE3(event_t e)
{
if(e == EV_DO) {
if(count > 5) {
trans(STATE1);
}
}
}
void trans(state_t next)
{
if(state) {
state(EV_EXIT);
}
state = next;
state(EV_ENTER);
}
int main(void) {
trans(STATE1);
for(;count < 200; count++) {
state(EV_DO);
}
return 0;
}