蜘蛛织网:使用二维函数指针数组实现表驱动状态机

引言
  • 状态机在嵌入式系统、协议解析等场景的核心作用
  • 传统switch-case实现状态机的局限性(冗余、难以维护)
  • 表驱动法的优势:逻辑与数据分离,扩展性高
核心概念解析
  • 状态机三要素:状态(State)、事件(Event)、动作(Action)
  • 二维函数指针数组
    • 定义:void (*FsmTableChart[MAX_STATES][MAX_EVENTS])(void*)
    • 索引:行代表当前状态,列代表触发事件,单元存储处理函数
  • 蛛织网隐喻:状态转移路径如同蜘蛛网结构,函数指针表是网的“编织规则”
    实现步骤

    状态与事件枚举

typedef enum fsm_state
{
    idle =0,
    running,
    pause,
    stop,
}fsm_state_t;
typedef struct fsm_struct
{
    bool (*check)(void);               //触发事件
    void (*init)(void);                //执行动作
    fsm_state_t  fsm_next_state;      //跳转状态
    fsm_state_t  fsm_current_state;   //下一状态
}fsm_struct_t;

函数指针表定义与初始化

const fsm_struct_t FsmTableChart[][3]=
{
  /*状态       分支1: 判断条件,执行动作,跳转状态        分支2: 判断条件,执行动作,跳转状态      分支3: 判断条件,执行动作,跳转状态*/  
   [idle]    = {check_idle,   init_idle,running},        {check_pause,init_pause,stop },     {check_stop, init_stop, idle},
   [running] = {check_running,init_running,pause},       {check_idle, init_idle,idle  },     {check_stop ,init_stop ,idle},
   [pause]   = {check_pause,  init_pause,stop},          {check_idle, init_idle,idle  },     {check_stop ,init_stop ,idle}
}

FsmTableChart[][3],行:表示状态,可以自定义多种状态。列:事件分支,三个大括号里面 可以理解为三个分支。即在该状态下,不同的检查函数触发不同的分支。类似于剧本杀多种结局,多条分支的玩法。

状态期间持续动作

定义每个状态的持续动作,这一步的思想为:当处在当前状态时就持续执行当前状态动作。比如:处于空闲状态(IDLE),持续监测信号;处于运行状态(RUNNING),持续计算PID;处于停止状态(STOP),持续监测唤醒信号等等;

void (*State_inits_Func[])()=      //定义状态机当前状态执行函数,该函数数组与状态一一对应
{
    acting_idle, acting_running, acting_pause, acting_stop
};

状态机引擎实现(放入轮询或者定时器)

fsm_struct_t FsmPublicTask={
    .check=NULL,
    .init =NULL,
    .fsm_next_state =idle,
    .fsm_current_state=idle,
    
};

void Fsm_task_Polling()
{
    State_inits_Func[FsmPublicTask.fsm_current_state]();   //进入循环执行
    for(int i=0;i<3;i++)
    {
        if(FsmTableChart[FsmPublicTask.fsm_current_state][i].check != NULL)
        {
          if(FsmTableChart[FsmPublicTask.fsm_current_state][i].check() == true)
          {
            if(FsmTableChart[FsmPublicTask.fsm_current_state][i].init!= NULL)
            {
                FsmTableChart[FsmPublicTask.fsm_current_state][i].init();
            }
                FsmPublicTask.fsm_current_state= FsmTableChart[FsmPublicTask.fsm_current_state][i].fsm_next_state;
          }
        }
    }
}
    
优化技巧
  • 空事件处理:用NULL指针跳过无效状态-事件组合,减少条件判断
  • 分层状态机:通过多级函数指针表实现层次化状态(如HFSM)
  • 动态表切换:运行时更换指针表以支持多模式状态机
应用案例
  • 通信协议解析:TCP状态机(SYN_RECEIVED → ESTABLISHED)
  • UI系统:按钮状态迁移(PRESSED → HOLD → RELEASED)
  • 工业控制:电机控制状态(STANDBY → ACCELERATION → CRUISE)
对比分析
  • switch-case对比
    • 代码量减少50%以上(示例:Modbus协议解析器)
    • 新增状态时仅需扩展表,无需修改逻辑代码
结语
  • 二维函数指针表是C语言实现高效状态机的“银弹”
  • 鼓励在资源敏感型项目中替代传统条件分支结构
  • 第一次发帖有错误恳请各位友友指正
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值