C语言实现简单有限状态机(FSM)

有限状态机(finite state machine)简称FSM,表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用。FSM是一种逻辑单元内部的一种高效编程方法,在服务器编程中,服务器可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。
状态机实现的方式有多种,下面讲述三种.

使用if/else if语句实现的FSM

使用if/else if语句是实现的FSM最简单最易懂的方法,我们只需要通过大量的if /else if语句来判断状态值来执行相应的逻辑处理。
看看下面的例子:

#include <stdio.h>
enum year_state
{
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER
};
 
void spring_thing()
{
    printf("hello spring\n");
}
void summer_thing()
{
    printf("hello summer\n");
}
void autumn_thing()
{
    printf("hello autumn\n");
}
void winter_thing()
{
    printf("hello winter\n");
}
 
int main()
{
    int state = SPRING;
    while (1)
    {
        if (state == SPRING)
        {
            spring_thing();//相应的处理
            state = SUMMER;//状态改变
        }
        else if (state == SUMMER)
        {
            summer_thing();
            state = AUTUMN;
        }
        else if (state == AUTUMN)
        {
            autumn_thing();
            state = WINTER;
        }
        else if (state == WINTER)
        {
            winter_thing();
            state = SPRING;
        }
        sleep(1);
    }
 
    return 0;
}

简单易懂,这里实现了四季的更替,因为只有四种状态,所以逻辑清楚,试想如果有个几十种状态,我们的if else将会变得十分之长,维护起来很麻烦,删减和添加状态变得不方便.但是通过这个例子我们认识到状态机的内涵.
如下图:
在这里插入图片描述
在状态1时,遇到一个事件,此刻发生状态转换,一般在状态转换前,先要进行事件的处理,然后改变状态位.然后进入状态2,以此类推.

使用switch case

这种做法和if else类似,结构上更清楚一些,代码如下:


int main()
{
    int state = SPRING;
    while (1)
    {
        switch(state){
        case SPRING:
            spring_thing();
            state = SUMMER;
            break;
        case SUMMER:
            summer_thing();
            state = AUTUMN;
            break;
        case AUTUMN:
            autumn_thing();
            state = WINTER;
            break;
        case WINTER:
            winter_thing();
            state = SPRING;
            break;
        default:
            break;

        }
        sleep(1);
    }

    return 0;
}

函数指针实现FSM

使用函数指针实现FSM的思路:建立相应的状态表和动作查询表,根据状态表、事件、动作表定位相应的动作处理函数,执行完成后再进行状态的切换。

当然使用函数指针实现的FSM的过程还是比较费时费力,但是这一切都是值得的,因为当你的程序规模大时候,基于这种表结构的状态机,维护程序起来也是得心应手。

首先我们画出这个表
在这里插入图片描述
代码:

#ifndef _FSM_H_
#define _FSM_H_
 #include <stdio.h>
#include <stdint.h>
#include <stddef.h>

//===============
/*状态号*/
typedef  enum {
  walk_state = 1,
  talk_state,
  fly_state,
  run_state,
  jump_state
}FSM_STATE,*FSM_STATE_P;
/*事件*/
typedef  enum {
  walk_event = 1,
 talk_event,
  fly_event,
  run_event,
  jump_event
}FSM_EVENT, *FSM_EVENT_P;

typedef struct FsmTable_s
{
    uint8_t event;                /* 触发事件名字 */
    uint8_t CurState;             /* 当前状态 */
    void (*eventActFun)(void *);  /* 动作函数 */
    uint8_t NextState;            /* 跳转状态 */
}FsmTable_T,*FsmTable_T_P;
 
typedef struct FSM_s
{
    FsmTable_T *FsmTable;         /* 状态迁移表 */
    uint8_t curState;             /* 状态机当前状态 */
    uint8_t stuMaxNum;            /* 状态机状态迁移数量 */
}FSM_T, *FSM_T_P ;
 
/*********************************************************************************
使用方法:1.创建FSM_T对象;
          2.创建FsmTable_T表;
          3.调用FSM_Init()初始化;
          4.程序轮询FSM_EventHandle()运行状态机。
*********************************************************************************/
void FSM_Regist(FSM_T *pFsm, FsmTable_T *pTable, uint8_t stuMaxNum, uint8_t curState);
void FSM_EventHandle(FSM_T *pFsm, uint8_t event, void *parm);
 
#endif
#include "fsm.h"
 
/*==================================================================
* Function  : FSM_StateTransfer
* Description : 状态转换
* Input Para  : 
* Output Para : 
* Return Value: 
==================================================================*/
static void FSM_StateTransfer(FSM_T *pFsm, uint8_t state)
{
    pFsm->curState = state;
}
 
/*==================================================================
* Function  : FSM_EventHandle
* Description : 状态机处理函数
* Input Para  : pFsm状态机对象, event触发事件, parm动作执行参数
* Output Para : 
* Return Value: 
==================================================================*/
void FSM_EventHandle(FSM_T *pFsm, uint8_t event, void *parm)
{
    /*创建一个状态对象指向当前的状态*/
    FsmTable_T *pAcTable = pFsm->FsmTable;
    /*当前状态要执行的事件函数*/
    void (*eventActFun)(void *) = NULL;
    uint8_t NextState;
    /*获取当前状态号*/
    uint8_t CurState = pFsm->curState;
    uint8_t flag = 0;
      /*遍历状态链表*/
    for (uint8_t i = 0; i < pFsm->stuMaxNum; i++)
    {
        /*当且仅当当前状态下来个事件才执行*/
        if (event == pAcTable[i].event && CurState == pAcTable[i].CurState)
        {
            /*允许执行状态事件*/
            flag = 1;
            /*获取当前状态事件执行函数*/
            eventActFun = pAcTable[i].eventActFun;
            /*获取下一个状态事件号*/
            NextState = pAcTable[i].NextState;
            break;
        }
    }
    /*开始执行状态事件*/
    if (flag)
    {
        /*如果当前状态事件有需要执行的函数,就执行*/
        if (eventActFun != NULL)
        {
            eventActFun(parm);  // 执行相应动作
        }
        /*状态转换*/
        FSM_StateTransfer(pFsm, NextState); 
    }
    else
    {
        /*do nothing*/
    }
}
 
/*==================================================================
* Function  : FSM_Init
* Description : 状态机注册
* Input Para  : pFsm状态机对象,pTable状态迁移表,stuMaxNum迁移表数量
*                           curState当前状态
* Output Para : 
* Return Value: 
==================================================================*/
void FSM_Regist(FSM_T *pFsm, FsmTable_T *pTable, uint8_t stuMaxNum, uint8_t curState)
{
    pFsm->FsmTable = pTable;
    pFsm->curState = curState;
    pFsm->stuMaxNum = stuMaxNum;
}

//====================函数声明====================================
void walk(void *);
void talk(void *);
void fly(void *);
void run(void *);
void jump(void *);

//==========================================================

int  main(void )
{
/*创建FSM_T对象*/
FSM_T  fsm = {0};
FSM_T_P  fsm_p = &fsm;
/*创建FsmTable_T表*/
FsmTable_T  fsm_table[5] = {
{walk_event , walk_state , walk, talk_state},
{talk_event , talk_state , talk, run_state},
{ fly_event , fly_state  ,fly , jump_state},
{run_event ,run_state ,run,fly_state},
{jump_event,jump_state,jump,walk_state}
};
char  i = 1;
/*FSM_Init()初始化*/
FSM_Regist(fsm_p, fsm_table,5, walk_state);
int EVENT  = 0;
while(1)
     {
        
        /*轮询运行状态机*/
     FSM_EventHandle(fsm_p,EVENT,&i);
   EVENT++;
   if(EVENT>5) EVENT = 1;
     }
     return  0;
}



//========================函数实现==================================
void walk(void * t)
{
printf("我正在走\r\n");
}
void talk(void * t)
{
printf("我正在讲话\r\n");
}
void fly(void * t)
{
printf("我正在飞机上\r\n");

}
void run(void * t )
{
printf("我正在跑步\r\n");
}
void jump(void * t)
{
printf("我正在跳高\r\n");
}

//===========================================================

运行:
在这里插入图片描述

参考文章链接:https://www.jianshu.com/p/917c0fb8778b?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include int main() { int state_key = 1; //钥匙状态 为1时钥匙区有钥匙,为时钥匙区 无钥匙 int state_hold = 0; // 钥匙持有状态 为1时持有钥匙,为时 未持有钥匙 int state_door = 0; //门状态 0:关闭 1:打开 int state_lock = 1; //上锁状态 1:上锁 0:解锁 int order; // 用于存放用户输入指令 printf("this is a game.\n"); printf ("if you want to OPEN THE DOOR ,input 1\n"); printf ("if you want to CLOSE THE DOOR ,input 2\n"); printf ("if you want to LOCK THE DOOR ,input 3\n"); printf ("if you want to UNLOCK THE DOOR,input 4\n"); // printf ("if you want to LOCK THE DOOR ,input 5\n"); printf("please input the order\n"); while(1) { scanf("%d",&order); // if(order!=(1||2||3||4)) // { // printf("worng input ,please input again.\n"); // continue; // } switch(order) { case 1 : if(state_door==1) { printf("the door has been opened before\n"); break; } if(state_lock==1) { printf("the door has been lock\n"); break; } state_door=1; break; case 2: if(state_door==0) { printf("the door has been closed before\n"); break; } if(state_lock==1) { printf("the door has been lock\n"); break; } state_door=0; break; case 3: if(state_door==1) { printf("the door has been opened before\n"); break; } if(state_lock==1) { printf("the door has been lock\n"); break; } state_lock=1; break ; case 4: if(state_door==1) { printf("the door has been opened before\n"); break; } if(state_lock==0) { printf("the door has not been lock\n"); break; } state_lock=0; break ; } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值