基于函数指针的状态机c语言实现(简单易懂)

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,状态:%d\r\n", x,state);
    }  
    for (x = 10; x > 0; x--)
    {
        fsm_run(&state);
        printf("当前 x的值为:%d,状态:%d\r\n", 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,状态:%d\r\n", x,state);
    }
    
    for (x = 10; x > 0; x--)
    {
        fsm_run(&state);
        printf("当前 x的值为:%d,状态:%d\r\n", x,state);
    }
    while (1);

}

当我们需要添加新的状态和箭头的时候,只需要添加状态变量、规则即可。

个人觉得写得应该挺简单的了(可能用词不是那么专业),不知道你们感觉怎么样?如有问题,欢迎指出。
在这里插入图片描述

  • 14
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值