概述
0 前言
由于项目所需,需要一个状态机进行状态的判定,之前一直使用if else 和switch case 的方式。虽说能用,但是修改和添加会比较麻烦。所以就想照着网上别人的例子来写一个。但是网上的代码要么写得太好,要么功能不全。所以我就自己琢磨这写一个简单一点的教程,希望能帮到你。
这里关于状态机就不介绍了,直入主题。
1 举例与分析
这里有一个简单的状态图
图中共有3种元素,状态、箭头(可行方向)、转移条件。
其中,1、2、3、4为状态。箭头为可行方向,箭头上的语句为转移条件(x,y为外部传入变量)。比如,系统状态要从状态1要变成状态2,需要满足x==y的条件。
我们将 当前状态—转移条件—下一个状态 定义为一个规则,如图共有5个规则,分别为:
1--->(x==y)--->2 2--->(x>y)--->3 3--->(x==y)--->4 4--->(x<y)--->1 1--->(x>y)--->3
那么当满足规则的时候,状态便转移到下一个状态。
2 编程
(1)定义状态变量
这里使用枚举类型,图中有4个状态,因此
typedef enum {
state_1 = 1,
state_2,
state_3,
state_4
}State;
(2)定义规则结构体
包含当前状态、下一个状态、转移条件
typedef struct {
State cur_state;//当前状态
State next_state;//下个状态
bool (*trans_function)(void);//转移函数 此处使用函数指针 在初始化时需要绑定具体函数如: bool test(void)
}State_Rule;
(3)定义具体的每一条转移函数
根据箭头上的转移条件进行编写
bool trans_1to2(void)
{
return (x == y);
}
bool trans_1to3(void)
{
return (x > y);
}
bool trans_2to3(void)
{
return (x > y);
}
bool trans_3to4(void)
{
return (x == y);
}
bool trans_4to1(void)
{
return (x < y);
}
(4)规则表初始化
有几条规则就定义几个,使用数组方便后续遍历
State_Rule state_rule[] = {
{state_1,state_2,trans_1to2},
{state_2,state_3,trans_2to3},
{state_3,state_4,trans_3to4},
{state_4,state_1,trans_4to1},
{state_1,state_3,trans_1to3}
};
(5)状态机运行函数
void fsm_run(State *cur_state)//传入当前状态,因为需要对其进行修改,所以传变量指针
{
for (int i = 0; i < 5; i++)
{
if ((state_rule[i].cur_state == *cur_state) && (state_rule[i].trans_function() == true))//当前状态相等并且转移条件为真
{
//这里可以添加自己需要执行的代码
*cur_state = state_rule[i].next_state;//转移为下一个状态
}
}
}
2验证
为了验证我们的代码是否成功,我们假设初始状态为state_1,定义变量x和y。其中y=5,x从1增加到10,再从10减小到1。
根据规则,我们先理清转移过程:当x=5时(x=y),系统状态从1变成2;当x=6时(x>y),系统状态从2变成3;然后再次当x=5时(x=y),系统状态从3变成4,;当x=4时(x<y),系统状态从4变成1。
int x;
int y = 5;
int main(void) {
State state = state_1;
for (x = 1; x < 10; x++)
{
fsm_run(&state);
printf("当前 x的值为:%d,状态:%drn", x,state);
}
for (x = 10; x > 0; x--)
{
fsm_run(&state);
printf("当前 x的值为:%d,状态:%drn", x,state);
}
while (1);
}
运行结果如图,符合构想。nice! (c语言运行软件很多,这里用的vs2019)
3 整体代码
/*state.c*/
#include <stdio.h>
int x;
int y = 5;
typedef enum {
state_1 = 1,
state_2,
state_3,
state_4
}State;
bool trans_1to2(void)
{
return (x == y);
}
bool trans_1to3(void)
{
return (x > y);
}
bool trans_2to3(void)
{
return (x > y);
}
bool trans_3to4(void)
{
return (x == y);
}
bool trans_4to1(void)
{
return (x < y);
}
typedef struct {
State cur_state;//当前状态
State next_state;//下个状态
bool (*trans_function)(void);//转移函数 此处使用函数指针 在初始化时需要指向具体函数如: bool test(void)
}State_Rule;
State_Rule state_rule[] = {
{state_1,state_2,trans_1to2},
{state_2,state_3,trans_2to3},
{state_3,state_4,trans_3to4},
{state_4,state_1,trans_4to1},
{state_1,state_3,trans_1to3}
};
void fsm_run(State *cur_state)//传入当前状态,因为需要对其进行修改,所以传变量指针
{
for (int i = 0; i < 5; i++)//遍历所有规则
{
if ((state_rule[i].cur_state == *cur_state) && (state_rule[i].trans_function() == true))//当前状态相等并且转移条件为真
{
//这里可以添加自己需要执行的代码
*cur_state = state_rule[i].next_state;//转移为下一个状态
}
}
}
int main(void) {
State state = state_1;
for (x = 1; x < 10; x++)
{
fsm_run(&state);
printf("当前 x的值为:%d,状态:%drn", x,state);
}
for (x = 10; x > 0; x--)
{
fsm_run(&state);
printf("当前 x的值为:%d,状态:%drn", x,state);
}
while (1);
}
当我们需要添加新的状态和箭头的时候,只需要添加状态变量、规则即可。
个人觉得写得应该挺简单的了(可能用词不是那么专业),不知道你们感觉怎么样?如有问题,欢迎指出。
最后
以上就是发嗲玉米为你收集整理的基于函数指针的状态机c语言实现(简单易懂)0 前言1 举例与分析2 编程2验证3 整体代码的全部内容,希望文章能够帮你解决基于函数指针的状态机c语言实现(简单易懂)0 前言1 举例与分析2 编程2验证3 整体代码所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复