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

时间: 2024-08-12 08:17:03

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

指针数组与数组指针 和 函数指针与函数指针数组

很容易混淆的概念其实并不难理解 1,指针数组: 看字面意思就知道这一定是一个数组,里面的原酸全部是指针 例如,定义一个简单的指针数组 char  *p[10];   //这就是一个包含十个字符指针的数组. 例: #include<stdio.h>int main(){ char *p[7]; char arr[] = "abcdef"; int i = 0; for (i = 0; i < 7; i++) {  p[i] = arr; } printf("%

【C/C++学院】0726-cppIDE/一级指针/指针数组/函数指针/函数指针数组/二级指针

[送给在路上的程序员] 对于一个开发者而言,能够胜任系统中任意一个模块的开发是其核心价值的体现. 对于一个架构师而言,掌握各种语言的优势并可以运用到系统中,由此简化系统的开发,是其架构生涯的第一步. 对于一个开发团队而言,能在短期内开发出用户满意的软件系统是起核心竞争力的体现. 每一个程序员都不能固步自封,要多接触新的行业,新的技术领域,突破自我. cppIDE 使用mfc和codeblocks中的mingw编译器.执行system命令中的bat批处理脚本. 一级指针 指针,结构体struct,

函数指针、函数指针数组

参考:百度百科 |函数指针|词条. 指针_函数,就不说了.自己感觉就是So-easy的.[ 声明格式:returnType *Function(arguments); ] 重点是 函数指针,以及突然冒出来的 函数指针数组;(特别说明,我习惯先写代码,再写注释:情况A:代码在左,注释向右.情况B:代码在上,注释在下.) 函数指针,我形象的描述 函数<-指针,(文中一切有问题请指正,谢谢).[声明格式: returnType(*pointer)(arguments); ] 举例: int fun(i

转:函数指针数组的妙用(I)

转自:http://blog.sina.com.cn/s/blog_4c78b35f010008hi.html 笔者在开发某软件过程中遇到这样一个问题,前级模块传给我二进制数据,输入参数为 char* buffer 和 int length,buffer是数据的首地址,length表示这批数据的长度.数据的特点是:长度不定,类型不定,由第一个字节(buffer[0])标识该数据的类型,共有256(2的8次方)种可能性.我的任务是必须对每一种可能出现的数据类型都要作处理,并且我的模块包含若干个函数

C#委托与C语言函数指针及函数指针数组

C#委托与C语言函数指针及函数指针数组 在使用C#时总会为委托而感到疑惑,但现在总新温习了一遍C语言后,才真正理解的委托. 其实委托就类似于C/C++里的函数指针,在函数传参时传递的是函数指针,在调用的时候通过指针访问这个函数. 在C语言中函数指针的申明如下: //可以理解为申明一个指着变量 Func ,它的类型是 返回Type(可以为 void )类型的参数,接收 (Type one,Type two,...)类型的//参数(可以不接受参数). Type *Func(Type one,Type

C语言中函数指针数组浅析

发现问题 问题分析 示例代码 发现问题 今天,在阅读Linux内核中关于socket的源代码时,遇到了下面一段代码: struct proto_ops { int family; struct module *owner; int (*release) (struct socket *sock); int (*bind) (struct socket *sock, struct sockaddr *myaddr, int sockaddr_len); int (*connect) (struct

函数指针与函数指针数组的使用方法

转自:http://blog.csdn.net/feitianxuxue/article/details/7300291 函数指针与函数指针数组的使用方法 函数指针: 函数指针包含函数在内存中的地址.数组名实际上就是数组的第一个元素在内存中的地址,类似地,函数名实际上也是执行这个函数任务的代码在内存中的起始地址. 函数指针可以传递给函数.从函数返回.保存在数组中.赋予另一个函数指针或者调用底层函数. 下面我们用数值算法accumulate讨论下函数指针的用法.accumulate是一种常用的ST

入职培训笔记记录--day9(1、指针函数与函数指针、函数指针数组 2、malloc memset 3、递归函数 4、结构体 5、共用体---》大小端 6、枚举)

1.指针函数与函数指针.函数指针数组 指针函数:返回值为指针的函数 char *fun() { char str[] = "hello world"; return str; } int main() { char *p = fun(); puts(p); return 0; } 编译时,会出现警告,返回了一个已经被释放掉的内存空间的首地址解决方法:1.static 2.char *str = "hello world"; 3.malloc 注意:使用完后要free

C语言的函数指针数组(好绕啊~)

int *(*p(int))[3] 今天有人问这个是啥?我一看直接就懵逼了…… 下面做一些简单的分析. int p; //这是整数型变量p int *p; //这是整数型指针p int *p[3]; //这是长度为3的整数型指针数组p,元素为整数型指针 int (*p)[3]; //这是一个数组指针,指向一个长度为3的整数型数组 int p(int); //这是函数声明,形参:整数型 ,返回值:整数型 等同于 int p(int x); int *p(int); //这是函数声明,形参:整数型