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
C/C++用状态转移表联合函数指针数组实现状态机FSM的更多相关文章
- C 函数指针 函数指针数组 转移表
内容来自<c和指针>,整理后方便个人理解 高级声明 cdel程序可以方便的给出声明的释义 指向函数的指针 int ( *f ) ( int n_values, float amount ) ...
- c语言.函数指针数组
函数指针: 一个指向函数的指针.一般用函数名表示. 函数指针数组:元素为函数指针的数组.转移表.c语言中函数不可以定义为数组,只能通过定义函数指针来操作. #include<stdio.h> ...
- 转:函数指针数组的妙用(I)
转自:http://blog.sina.com.cn/s/blog_4c78b35f010008hi.html 笔者在开发某软件过程中遇到这样一个问题,前级模块传给我二进制数据,输入参数为 char* ...
- C++基础——函数指针 函数指针数组
==================================声明================================== 本文版权归作者所有. 本文原创,转载必须在正文中显要地注明 ...
- typedef 函数指针 数组 std::function
1.整型指针 typedef int* PINT;或typedef int *PINT; 2.结构体 typedef struct { double data;}DATA, *PDATA; //D ...
- C#委托与C语言函数指针及函数指针数组
C#委托与C语言函数指针及函数指针数组 在使用C#时总会为委托而感到疑惑,但现在总新温习了一遍C语言后,才真正理解的委托. 其实委托就类似于C/C++里的函数指针,在函数传参时传递的是函数指针,在调用 ...
- C/C++ 一段代码区分数组指针|指针数组|函数指针|函数指针数组
#include<stdio.h> #include<stdlib.h> #include<windows.h> /* 举列子说明什么是函数指针 */ //以一个加 ...
- C/C++ 不带参数的回调函数 与 带参数的回调函数 函数指针数组 例子
先来不带参数的回调函数例子 #include <iostream> #include <windows.h> void printFunc() { std::cout<& ...
- C 函数指针数组
名字有点绕口,其实更应该翻译为指针函数数组. 记录下对Head-First C这一节的理解,几乎每天班车上都会咪两眼,几乎每次都是看不懂,敲一敲的时候才有些明白. 通俗点讲,这功能解决的是,具有同种签 ...
随机推荐
- Zuma (区间DP)
Genos recently installed the game Zuma on his phone. In Zuma there exists a line of n gemstones, the ...
- TCP内核参数
tcp_syn_retries :INTEGER默认值是5对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃.不应该大于255,默认值是5,对应于180秒左右时间.(对于大负载而物理通信良 ...
- shell的格式化输出命令printf
printf 命令用于格式化输出, 是echo命令的增强版.它是C语言printf()库函数的一个有限的变形,并且在语法上有些不同. 注意:printf 由 POSIX 标准所定义,移植性要比 ech ...
- cf396B On Sum of Fractions
Let's assume that v(n) is the largest prime number, that does not exceed n; u(n) is the smallest pri ...
- oracle的split函数
PL/SQL 中没有split函数,需要自己写. 代码: create or replace type type_split as table of varchar2(50); --创建一个 typ ...
- mysql 插入replace改变原有数据某些字段
完整原型:(主要看下面例子) replace into rpt_ci_cinema_seller_shift_dt ( BIZ_DATE,CINEMA_CD,SELLER_CD,LOCATION_CD ...
- PHP中使用GD库方式画时钟
<!--demo.html中内容--> <body> <img id="time" src="test.php" /> &l ...
- zoj 2562 反素数
题目大意:求n范围内最大的反素数(反素数定义:f(x)表示x的因子数,f(x)>f(x1) (0<x1<x)) x用质因数形式为:x=a1^p1*a2^p2......an^pn(a ...
- 【HDOJ6223】Infinite Fraction Path(后缀数组,倍增)
题意: 给一个长度为n的字符串s[0..n-1],但i的后继不再是i+1,而是(i*i+1)%n,求所有长度为n的“子串”中,字典序最大的是谁 n<=150000,s[i]=0..9 思路:后缀 ...
- android 完美退出应用程序。
Android 程序在点击回退键时,如果只有一个activity,调用finish()方法就能退出界面,如果有多个界面,在调用该方法时,只会销毁当前的activity,显示栈顶的其它activity, ...