首页 > 代码库 > C/C++用状态转移表联合函数指针数组实现状态机FSM

C/C++用状态转移表联合函数指针数组实现状态机FSM

状态机在project中使用很的频繁,有例如以下常见的三种实现方法:
1. switch-case 实现。适合简单的状态机。
2. 二维状态表state-event实现。逻辑清晰。可是矩阵通常比較稀疏,并且维护麻烦。
3. 用状态转移表stateTransfer Table实现,数组大小等于状体转移边个数,易扩展;
以下用一个样例来进行具体说明,描写叙述的例如以下场景:

描写叙述对象:门
状态:开着、关着、锁着 (这里的关着指关了但未锁的状态)
事件:开门、关门、上锁、解锁

代码实现用枚举来定义状态和事件,操作数据节点转移到目的状态用函数实现。枚举本身默认是从0開始的int类型,利用这个特点将状态转移函数放到函数指针数组中与状态相应起来。方便操作。
核心数据结构例如以下:

状态:枚举类型
事件:枚举类型
状态转移结构体:{当前状态、事件、下个状态},定义一个全局数组来使用
状态变更函数:到下个状态(放到数组中与状态枚举相应起来)

此种实现方法easy扩展,添加状态和事件都比較easy。

假设存在一个状态通过相应事件能够转移到多个状态的情形,则能够扩展状态转移函数。或者在状态转移结构中添加一个推断函数字段。
代码实现例如以下:

#include <iostream>
using namespace std;

typedef enum{
    OPENED,
    CLOSED,
    LOCKED,
}  State;

typedef enum{
    OPEN,
    CLOSE,
    LOCK,
    UNLOCK
} Event;

typedef struct{
    State currentState;
    Event event;
    State NextState;
} StateTransfer;

typedef struct{
    State state;
    int transferTimes;
}Door;

StateTransfer g_stateTransferTable[]{
    {OPENED, CLOSE,  CLOSED},
    {CLOSED, OPEN,   OPENED},
    {CLOSED, LOCK,   LOCKED},
    {LOCKED, UNLOCK, CLOSED},
};

void toOpen(Door& door);
void toClose(Door& door);
void toLock(Door& door);
typedef void (*pfToState)(Door& door);
pfToState g_pFun[] = {toOpen, toClose, toLock}; //状态枚举值相应下标

void toOpen(Door& door){
    door.state = OPENED;
    cout << "open the door!\n";
}

void toClose(Door& door){
    door.state = CLOSED;
    cout << "close the door!\n";
}

void toLock(Door& door){
    door.state = LOCKED;
    cout << "lock the door!\n";
}

void transfer(Door& door,const Event event){
    for (int i = 0; i < sizeof(g_stateTransferTable)/sizeof(StateTransfer); ++i) {
        if(door.state == g_stateTransferTable[i].currentState &&
           event == g_stateTransferTable[i].event){
            g_pFun[g_stateTransferTable[i].NextState](door);
            door.transferTimes++;
            cout << "transfer ok!\n";
            return;
        }
    }
    cout << "This event cannot transfer current state!!\n";
    return;
}

void printDoor(const Door& door){
    string stateNote[] = {"opened","closed","locked"}; // 下标正好相应状态枚举值
    cout << "the door‘s state is: " << stateNote[door.state] << endl;
    cout << "the door transfer times is: " << door.transferTimes << endl;
}

int main(){
    Door door = {CLOSED, 0};
    printDoor(door);
    transfer(door, OPEN);
    printDoor(door);
    transfer(door, LOCK);
    printDoor(door);
    transfer(door, CLOSE);
    printDoor(door);
    return 0;
}

执行结果例如以下:

the door’s state is: closed
the door transfer times is: 0
open the door!
transfer ok!
the door’s state is: opened
the door transfer times is: 1
This event cannot transfer current state!!
the door’s state is: opened
the door transfer times is: 1
close the door!
transfer ok!
the door’s state is: closed
the door transfer times is: 2

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

C/C++用状态转移表联合函数指针数组实现状态机FSM