天天看點

用函數指針來實作狀态機

狀态機的基本實作手段是​

​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;
}