之前写过一篇状态机的实用文章,很多朋友说有几个地方有点难度不易理解,今天给大家换种简单写法,使用函数指针的方法实现状态机。

状态机简介

有限状态机FSM是有限个状态及在这些状态之间的转移和动作等行为的数学模型,是一种逻辑单元内部的高效编程方法,可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。

函数指针实现FSM

使用函数指针实现FSM可以分为3个步骤

  1. 建立相应的状态表和动作查询表

  2. 根据状态表、事件、动作表定位相应的动作处理函数

  3. 执行完成后再进行状态的切换

代码实现步骤

  1. 定义状态数据的枚举类型
typedef enum {  state_1=1,  state_2,  state_3,  state_4}State;
  1. 定义事件的枚举类型
typedef enum{  event_1=1,  event_2,  event_3,  event_4,  event_5}EventID;
  1. 定义状态表的数据类型
typedef struct{    int event;   //事件    int CurState;  //当前状态    void (*eventActFun)();  //函数指针    int NextState;  //下一个状态}StateTable;
  1. 定义处理函数及建立状态表
void f121(){    printf("this is f121\n");}void f221(){    printf("this is f221\n");}void f321(){    printf("this is f321\n");}

void f122(){    printf("this is f122\n");}

StateTable fTable[] ={    //{到来的事件,当前的状态,将要要执行的函数,下一个状态}    { event_1,  state_1,    f121,  event_2 },    { event_2,  state_2,    f221,  event_3 },    { event_3,  state_3,    f321,  event_4 },    { event_4,  state_4,    f122,  event_1 },    //add your code here};
  1. 状态机类型,及状态机接口函数
/*状态机类型*/typedef struct {    int curState;//当前状态    StateTable * stateTable;//状态表    int size;//表的项数}fsmType;

/*状态机注册,给它一个状态表*/void fsmRegist(fsmType* pFsm, StateTable* pTable){    pFsm->stateTable = pTable;}

/*状态迁移*/void fsmStateTransfer(fsmType* pFsm, int state){    pFsm->curState = state;}

/*事件处理*/void fsmEventHandle(fsmType* pFsm, int event){    StateTable* pActTable = pFsm->stateTable;    void (*eventActFun)() = NULL;  //函数指针初始化为空    int NextState;    int CurState = pFsm->curState;    int maxNum = pFsm->size;    int flag = 0; //标识是否满足条件

    /*获取当前动作函数*/    for (int i = 0; i    {        //当且仅当当前状态下来个指定的事件,我才执行它        if (event == pActTable[i].event && CurState == pActTable[i].CurState)        {            flag = 1;            eventActFun = pActTable[i].eventActFun;            NextState = pActTable[i].NextState;            break;        }    }

    if (flag) //如果满足条件了    {        /*动作执行*/        if (eventActFun)        {            eventActFun();        }

        //跳转到下一个状态        fsmStateTransfer(pFsm, NextState);    }    else    {        printf("there is no match\n");    }}

附代码

代码直接复制过去就行啦,本想打包的,太麻烦了。

测试程序

//编译器:http://www.dooccn.com/cpp///来源:技术让梦想更伟大//作者:李肖遥#include 

typedef enum {  state_1=1,  state_2,  state_3,  state_4}State;

typedef enum{  event_1=1,  event_2,  event_3,  event_4,  event_5}EventID;

typedef struct {    int event;   //事件    int CurState;  //当前状态    void (*eventActFun)();  //函数指针    int NextState;  //下一个状态}StateTable;

void f121(){    printf("this is f121\n");}void f221(){    printf("this is f221\n");}void f321(){    printf("this is f321\n");}

void f122(){    printf("this is f122\n");}

StateTable fTable[] ={    //{到来的事件,当前的状态,将要要执行的函数,下一个状态}    { event_1,  state_1,    f121,  event_2 },    { event_2,  state_2,    f221,  event_3 },    { event_3,  state_3,    f321,  event_4 },    { event_4,  state_4,    f122,  event_1 },    //add your code here};

/*状态机类型*/typedef struct {    int curState;//当前状态    StateTable * stateTable;//状态表    int size;//表的项数}fsmType;

/*状态机注册,给它一个状态表*/void fsmRegist(fsmType* pFsm, StateTable* pTable){    pFsm->stateTable = pTable;}

/*状态迁移*/void fsmStateTransfer(fsmType* pFsm, int state){    pFsm->curState = state;}

/*事件处理*/void fsmEventHandle(fsmType* pFsm, int event){    StateTable* pActTable = pFsm->stateTable;    void (*eventActFun)() = NULL;  //函数指针初始化为空    int NextState;    int CurState = pFsm->curState;    int maxNum = pFsm->size;    int flag = 0; //标识是否满足条件

    /*获取当前动作函数*/    for (int i = 0; i    {        //当且仅当当前状态下来个指定的事件,我才执行它        if (event == pActTable[i].event && CurState == pActTable[i].CurState)        {            flag = 1;            eventActFun = pActTable[i].eventActFun;            NextState = pActTable[i].NextState;            break;        }    }

    if (flag) //如果满足条件了    {        /*动作执行*/        if (eventActFun)        {            eventActFun();        }

        //跳转到下一个状态        fsmStateTransfer(pFsm, NextState);    }    else    {        printf("there is no match\n");    }}

int main(){    fsmType pType;    fsmRegist(&pType,fTable);    pType.curState = state_1;    pType.size = sizeof(fTable)/sizeof(StateTable);

    printf("init state:%d\n\n",pType.curState);

    fsmEventHandle(&pType,event_1);    printf("state:%d\n\n",pType.curState);

    fsmEventHandle(&pType,event_2);    printf("state:%d\n\n",pType.curState);

    fsmEventHandle(&pType,event_3);    printf("state:%d\n\n",pType.curState);

    fsmEventHandle(&pType,event_4);    printf("state:%d\n\n",pType.curState);

    fsmEventHandle(&pType,event_2);    printf("state:%d\n\n",pType.curState);

    return 0;}

编译结果


总结

使用函数指针实现的FSM的过程还是比较费时费力的,但是这一切相对一大堆的if/else、switch/case来说都是值得的,当你的程序规模变得越来越大的时候,基于这种表结构的状态机,维护程序起来会清晰很多。

matlab watershed函数简单实现_函数指针方法实现简单状态机(附代码)相关推荐

  1. c++ 取成员函数地址_c及c++指针及引用简单解释(自学学习心得)

    从实参向形参传递参数时有两种方式可以使用: 1. 指针 使用指针传递时,如果目的是对实参的参数进行相关修改,则需要将实参变量的地址传递给形参,也就是说,形参需要定义为可以存放实参变量地址的变量,举个例 ...

  2. ostream作为函数返回值_函数的调用(一)

    函数作为计算机代码的一种抽象方式,它的作用不言而喻! 原文链接 认识函数: 定义:函数是一段代码的表示,是一段具有特定功能的,可重用的语句组 函数是一种功能的抽象,一般函数表达特定功能 两个作用:降低 ...

  3. python-return_全局局部变量_函数名用法_函数嵌套

    函数 1. return 返回值 作用: ​ 自定义函数的返回值,return 可以把值返回到函数的调用处 ​ return + 六大标准数据类型 , 还有类和对象,函数 ​ 如果不定义return ...

  4. python函数知识点总结_函数总结_python函数总结_高中函数知识点总结 - 云+社区 - 腾讯云...

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! postgresql窗口函数总结postgresql窗口函数总结 1窗口函数说明 ...

  5. 【C语言】函数的声明_函数定义_函数调用_函数递归 [函数的基本使用]

    文章目录 前言 1.函数是什么? 2.C语言中函数的分类 2.1 库函数 2.2 自定义函数 3.函数的参数 3.1 实际参数(实参): 3.2 形式参数(形参): 4.函数的调用 4.1 传值调用 ...

  6. filter函数的用法_函数周期表丨筛选丨表丨CALCULATETABLE

    CALCULATETABLE函数 CALCULATETABLE函数属于"筛选"类函数,隶属于"表函数". 某种意义上来说,CALCULATETABLE函数其实就 ...

  7. mysql函数输出参数_函数--返回值、参数和作用域

    一.函数的返回值--return的作用 1.return将return后面的值作为函数的输出返回值,当函数被调用时,返回值可以被其他变量接收.使用. 而print只是打印在控制台,一个函数如果没有re ...

  8. gwo算法matlab源代码,智能优化算法应用:基于GWO优化BP神经网络 - 附代码

    智能优化算法应用:基于GWO优化BP神经网络 - 附代码 智能优化算法应用:基于GWO优化BP神经网络 - 附代码 智能优化算法应用:基于GWO优化BP神经网络 文章目录智能优化算法应用:基于GWO优 ...

  9. 【Matlab 控制】仿真含时滞多智体一致性分析,附代码

    Matlab 仿真含时滞多智体一致性分析,附代码 系统结构如下图所示: clear; clc; % 2014_多智能体网络的一致性问题研究_纪良浩 % 此为Paper中的示例代码 % 例2.1: A ...

最新文章

  1. Django modules模块
  2. 蓝桥杯-8-1因式分解(java)
  3. win10使用虚拟光驱安装vcenter6.7
  4. IOS15之JSON的解析字典转模型
  5. python创建虚拟环境时出现拒绝访问_无法创建虚拟环境
  6. php验证旧密码,PHP最佳实践之过滤、验证、转义和密码
  7. IDEA代码行宽设置
  8. 【转】处理wording的一些参考
  9. 解密Twitch:一家游戏直播网站缘何价值10亿刀?
  10. Sodinokibi勒索病毒利用Flash漏洞强势来袭
  11. 英特尔 超核芯显卡 620mac_十代i9+3080显卡,男孩们的攒机快乐,还得拿出来显摆显摆!...
  12. Python进阶读书笔记之(四) set集合
  13. 什么是现汇买入价、现钞买入价、卖…
  14. 回声状态网络(echo state network,ESN)概述
  15. C++中string类下的begin,end,rbegin,rend的用法
  16. 女程序员们的结婚要求
  17. 语中最美的十大经典爱情句子
  18. 点击修改按钮,将数据显示在弹层窗口中,利用ajax实现
  19. 计算机安全知识有哪些方面,计算机安全包括哪些方面
  20. Grail:Uber是如何管理大规模基础设施的

热门文章

  1. SAP Spartacus的登录验证机制 - user login Authentication
  2. 汪子熙微信公众号的写作计划
  3. SAP Spartacus服务器端渲染模式下的调试方法
  4. SAP CRM settype COMM_PROD_VAR
  5. setProperty will trigger ui re-render 南京同事提的问题
  6. SAP fiori backend determine cache setting
  7. when is this.oModel in sap-ui-core.js initialized for navigation working case
  8. Organization model change - product line item EC
  9. FioriLaunchpad.html的三个round-trip
  10. 用纯CSS实现3D立方体效果