您现在的位置是:亿华云 > IT科技类资讯
「编程之美」函数指针方法实现简单状态机(附代码)
亿华云2025-10-03 20:30:28【IT科技类资讯】2人已围观
简介之前写过一篇状态机的实用文章,很多朋友说有几个地方有点难度不易理解,今天给大家换种简单写法,使用函数指针的方法实现状态机。状态机简介有限状态机FSM是有限个状态及在这些状态之间的转移和动作等行为的数学
之前写过一篇状态机的编程实用文章,很多朋友说有几个地方有点难度不易理解,美指针状态今天给大家换种简单写法,函数使用函数指针的实现方法实现状态机。
状态机简介
有限状态机FSM是简单机附有限个状态及在这些状态之间的转移和动作等行为的数学模型,是代码一种逻辑单元内部的高效编程方法,可以根据不同状态或者消息类型进行相应的编程处理逻辑,使得程序逻辑清晰易懂。美指针状态
函数指针实现FSM
使用函数指针实现FSM可以分为3个步骤
建立相应的函数状态表和动作查询表 根据状态表、事件、实现动作表定位相应的简单机附动作处理函数 执行完成后再进行状态的切换代码实现步骤
定义状态数据的枚举类型
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<maxNum; 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 <stdio.h> 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[] = { //{ 到来的事件,当前的状态,将要要执行的函数,云南idc服务商下一个状态} { 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<maxNum; 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来说都是值得的,当你的程序规模变得越来越大的时候,基于这种表结构的状态机,维护程序起来会清晰很多。
亿华云很赞哦!(3548)
相关文章
- 为什么现在中文域名觉得好?使用中文域名有什么好处?
- 如何打造一个高性能的前端智能推理引擎
- 一日一技:如何识别一张图片的格式
- Python爬虫实战:单线程、多线程和协程性能对比
- 域后缀首选.com,.net,然后是.cn。后缀选择不当,导致流量损失。域名是企业与互联网网址之间的链接,关键是企业在网络上存在的标志。因此,选择好域名是开展网上工作的首要重要条件。
- 用Operators管理多集群Kubernetes
- 重拾JAVA:这种编程语言为什么不行了?
- 建议收藏,22个Python迷你项目(附源码)
- 顶级域名可以增加企业品牌的价值。随着经济的快速发展,域名已不再是企业在网络中的独立地位。顶级域名的服务范围、企业产品、综合形象体现等,对于企业单位来说,顶级域名的重要性不言而喻。
- Protobuf序列化这么强,为什么不花五分钟学习一下呢?