C语言实现状态机
关于状态机,基础的知识点可以自行理解,讲解的很多,这里主要是想写一个有限状态机FSM通用的写法,目的在于更好理解,移植,节省代码阅读与调试时间,体现出编程之美。
传统的实现方案
-
if...else : 搞一大堆if else, 一个函数写很长很长......
-
swich...case : 也搞一大堆一个函数写很长很长......
先来看看最近做的一个项目,无线通信协议实现的状态机是什么样子的:

有三种类型的事件:上层下达的命令事件;下层到达的标志和数据传输事件;超时定时器超时事件。有10种状态,关联性很大,复杂了吧,这要是各种if/else的要写到什么时候呢。
在事件中判断状态,在状态中判断事件,横竖两种写法的代码都比较冗长,看起来呢也不大好,一旦增减,就又要动脑子重新梳理一遍,很累的。
怎么去写呢?其状态机原理:在根据当前状态(cur_state) 下,发生事件(event)后,转移到下一个状态号(nxt_state),决定执行的动作(action)。

这里我们首先定义一个结构体如下:
typedef struct {State curState;//当前状态EventID eventId;//事件IDState nextState;//下个状态Action action;//具体表现
}StateTransform;
我们假设有3种状态,这里可以随意增加,状态枚举如下:
typedef enum {state_1=1,state_2,state_3
}State;
我们假设有5个事件,也可以随意增加,事件ID枚举如下:
typedef enum{event_1=1,event_2,event_3,event_4,event_5
}EventID;
将其封装起来在StateMachine中:
typedef struct{State state;int transNum;StateTransform* transform;
}StateMachine;
具体流程:当前状态-有事件触发-跳到下个状态-具体表现,重构代码
StateTransform* findTranss(StateMachine* pSM, const EventID evt)
{int i;for (i = 0; i < pSM->transNum; i++) {if ((pSM->transform[i].curState == pSM->state) && (pSM->transform[i].eventId == evt)) {return &pSM->transform[i];}}return NULL;
}
状态机实现如下:
void runStateMachine(StateMachine* pSM, EventID evt) {StateTransform* pTrans;pTrans = findTranss(pSM, evt);if (pTrans == NULL){xil_printf( "CurState= %s Do not process enent: %s\r\n", pSM->state,evt);return;}pSM->state = pTrans->nextState;Action act = pTrans->action;if (act == NULL) {xil_printf( "change state to %s. No action\r\n",pSM->state);return;}act(&evt);
}
最后我模拟一些随机事件,我们只需要弄清楚事件ID,状态切换,具体表现就可以了,在代码中就是填写stateTran[] 这个表,一旦有增减事件,状态等等,也不需要再去使用switch/case,特费脑,其代码如下:
int run()
{StateMachine stateMachine;stateMachine.state = state_1;stateMachine.transNum = 7;StateTransform stateTran[] = {{state_1,event_3,state_2,f121},{state_1,event_4,state_2,NULL},{state_2,event_1,state_3,f231},{state_2,event_4,state_2,f221},{state_3,event_2,state_1,f311},{state_3,event_3,state_2,f321},{state_3,event_5,state_3,f331}};stateMachine.transform = stateTran;EventID inputEvent[15] = { event_1, event_2, event_3, event_4, event_5,event_1, event_2, event_3, event_4, event_5,event_1, event_2, event_3, event_4, event_5 };int i;for (i = 0; i < 15; i++) {runStateMachine(&stateMachine, inputEvent[i]);}return 0;
}
最后运行结果如下

总结:
状态机应用很广泛,也可以锻炼我们写代码的逻辑思维,看清问题的本质,写的代码才能赏心悦目,希望大家能够多多指点,找到编程的乐趣,欣赏到编程之美。
相关文章:
C语言实现状态机
关于状态机,基础的知识点可以自行理解,讲解的很多,这里主要是想写一个有限状态机FSM通用的写法,目的在于更好理解,移植,节省代码阅读与调试时间,体现出编程之美。 传统的实现方案 if...else : …...
交叉编译工具链arm-linux-gnueabihf的安装-ubuntu 20.04
前面下载安装步骤参考该博主的文章 http://t.csdn.cn/ZbjFX 另:本人对所遇到的环境变量的配置问题作补充 1.修改环境变量 建议直接在.bashrc文件作修改 ,修改方式相同 ( vi :视自己的编辑器而定) sudo vi ~/.bashrc 2.修改环境变量后,可…...
Java的类加载器
类加载 1、ClassLoader 用来加载 Class 文件 2、 系统内置的ClassLoader 通过双亲委托加载指定目录下的class和资源 3、 可以自定义ClassLoader 一般覆盖findClass() 4、ContextClassLoader 与线程相关,可以获取和设置,可以绕过双亲委托的机制。 三个类…...
Stable Diffusion web UI 部署详细教程
前言 本文使用 AutoDL 平台进行 Stable Diffusion web UI 云端部署 AutoDL 官网:AutoDL算力云 | 弹性、好用、省钱。租GPU就上AutoDL Stable Diffusion web UI 官网:AUTOMATIC1111/stable-diffusion-webui: Stable Diffusion web UI (github.com) 步…...
《深度学习计算机视觉 》书籍分享(包邮送书三本)
深度学习计算机视觉介绍 随着计算机技术的发展和进步,计算机视觉领域得到了广泛的关注和研究。而深度学习作为一种强大的机器学习方法,已经成为计算机视觉领域的重要工具之一。本文将介绍深度学习在计算机视觉中的应用和取得的成果。 深度学习是一种模…...
【使用 k 折叠交叉验证的卷积神经网络(CNN)】基于卷积神经网络的无特征EMG模式识别研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
微服务 Nacos配置热部署
在nacos中添加配置文件 在配置列表中添加配置, 注意:项目的核心配置,需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。 从微服务拉取配置 微服务要拉取nacos中管理的配置,并且与…...
国产调度器之光——Fsched到底有多能打?
这是一篇推荐我们速石自研调度器——Fsched的文章。 看起来在专门写调度器,但又不完全在写。 往下看,你就懂了。 本篇一共五个章节: 一、介绍一下主角——速石自研调度器Fsched 二、只要有个调度器,就够了吗? 三…...
LeetCode:53. 最大子数组和 - Python
53. 最大子数组和 问题描述: 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连续部分。 示例 1: 输入:nums [-…...
网站建设 之 react usestate
react着重在于“不可变动” 如果变动了怎么办呢?那就整个新的 局部变量/函数/jsx-》state/props-〉ref,依次越来越难变 每次state/props,局部变量/函数/jsx都是新的 既然函数是新的,那么就会有一个问题,回调函数用…...
第一讲使用IDEA创建Java工程——HelloWorld
一、前言导读 为了能够让初学者更快上手Java,不会像其他书籍或者视频一样,介绍一大堆历史背景,默认大家已经知道Java这么编程语言了。本专栏只会讲解干货,直接从HelloWord入手,慢慢由浅入深,讲个各个知识点,这些知识点也是目前工作中项目使用的,而不是讲一些老的知识点…...
BootstrapBlazor组件使用:数据注解
文章目录 前言BB数据注解数据注解源码数据注解简介注解简单实例[BB 编辑弹窗](https://www.blazor.zone/edit-dialog)[ValidateForm 表单组件](https://www.blazor.zone/validate-form)使用简介 前言 BootstrapBlazor(一下简称BB)是个特别好用的组件,基本上满足了大…...
MySQL 触发器
文章目录 1.简介2.行级与语句级触发器3.触发时机4.触发器优缺点5.创建触发器语法示例 6.查看触发器7.删除触发器参考文献 1.简介 触发器(Trigger)是与表关联的命名数据库对象,当表发生特定事件时激活。 触发器的一些用途是对要插入表中的值执…...
DPDK主从进程模式 rte_mempool_put失败
版本:19.11.6 情景:主进程应用rte_mempool_create创建mempool,rte_mempool_get获取数据;从进程应用rte_mempool_put归还数据 问题:从进程rte_mempool_put无法归还数据 原因:DPDK通过rte_mempool_ops_tab…...
ZooKeeper 的工作原理
ZooKeeper 的工作原理可以概括为以下几个方面: 1. 数据模型 ZooKeeper 使用树形目录节点(znode)来建模关键的数据,每个 znode 可以存储数据内容,也可以作为目录包括子节点。客户端可以在节点上设置监听器。 2. 一致性算法 ZooKeeper 使用 ZAB(ZooKeeper Atomic Broadcast)协议…...
【业务功能篇73】分布式ID解决方案
业界实现方案 1. 基于UUID2. 基于DB数据库多种模式(自增主键、segment)3. 基于Redis4. 基于ZK、ETCD5. 基于SnowFlake6. 美团Leaf(DB-Segment、zkSnowFlake)7. 百度uid-generator() 1.基于UUID生成唯一ID UUID:UUID长度128bit,32个16进制字符,占用存储空…...
Qt安卓开发经验技巧总结V202308
01:01-05 pro中引入安卓拓展模块 QT androidextras 。pro中指定安卓打包目录 ANDROID_PACKAGE_SOURCE_DIR $$PWD/android 指定引入安卓特定目录比如程序图标、变量、颜色、java代码文件、jar库文件等。 AndroidManifest.xml 每个程序唯一的一个全局配置文件&…...
【vue2】前端实现下载后端返回的application/octet-stream文件流
1、下载csv/txt时 此时无须修改接口的响应格式 let filenameRegex /filename[^;\n]*((["]).*?\2|[^;\n]*)/; let matches filenameRegex.exec(data.headers[content-disposition]); let blob new Blob([\uFEFF data.data], {//目前只有csv格式type: text/csv;charse…...
【Java】SM2Utils(国密 SM2 工具类)
基于 bouncycastle 实现 国密 SM2 <!-- 引入 bouncycastle --> <dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.70</version> </dependency>import lombok.Sneak…...
『C语言入门』初识C语言
文章目录 前言C语言简介一、Hello World!1.1 编写代码1.2 代码解释1.3 编译和运行1.4 结果 二、数据类型2.1 基本数据类型2.2 复合数据类型2.3 指针类型2.4 枚举类型 三、C语言基础3.1 变量和常量3.2 运算符3.3 控制流语句3.4 注释单行注释多行注释注释的作用 四、 …...
MCP39F501电能计量芯片:高精度单相计量方案与工程实践详解
1. 项目概述:为什么我们需要一颗专用的电能计量芯片?在智能家居、工业物联网和新能源领域,精确测量交流电(AC)的用电参数——比如电压、电流、功率、电能——是底层最核心的需求之一。你可能觉得,用个高精度…...
Perplexity提示工程精要(2024权威认证版):覆盖92%高频场景的12类黄金模板
更多请点击: https://intelliparadigm.com 第一章:Perplexity提示工程的核心原理与认知框架 Perplexity(困惑度)作为衡量语言模型预测能力的关键指标,其本质是模型对真实文本序列分布的负对数似然指数化表达。在提示工…...
终极Axel下载加速指南:让你的文件下载速度翻倍
终极Axel下载加速指南:让你的文件下载速度翻倍 【免费下载链接】axel Lightweight CLI download accelerator 项目地址: https://gitcode.com/gh_mirrors/ax/axel Axel是一款轻量级命令行下载加速工具,通过多线程技术显著提升文件下载速度。无论你…...
告别驱动烦恼:用TI官方CCS开发MSP430,为什么比第三方IAR更省心?
嵌入式开发者的效率革命:为什么TI官方CCS是MSP430开发的最优解? 在嵌入式开发领域,工具链的选择往往决定了项目的启动速度和开发体验。对于MSP430系列微控制器的开发者而言,面对IAR、GCC和TI官方的Code Composer Studio(CCS)等多种…...
自动售货机哪个品牌好?2026年选购避坑全攻略~YH
经常有朋友问我:“自动售货机到底选哪个牌子?”说实话,这个问题我之前也纠结过。市面上做自动售货机的品牌不下几十家,价格从几千到几万都有,广告一个比一个响。但真正用下来,才知道差别有多大。今天就把这…...
生态学家都在用的R包MixSIAR:手把手教你用贝叶斯模型搞定食物网溯源
生态数据分析实战:用MixSIAR实现贝叶斯食物网溯源 河口湿地的鱼类究竟以藻类还是陆源有机物为主要食物?这个看似简单的问题背后,隐藏着复杂的生态关系网络。传统稳定同位素分析方法虽然能提供部分答案,但当面对多个潜在食物源和不…...
从ARM Cortex-M到FPGA:手把手教你用AXI4-Lite搭建自定义外设(以Zynq-7000为例)
从ARM Cortex-M到FPGA:用AXI4-Lite实现自定义外设的工程实践 在嵌入式系统开发中,处理器与可编程逻辑的高效协同一直是提升性能的关键路径。当标准外设无法满足特定需求时,工程师往往需要在FPGA中设计定制硬件模块,并通过标准化总…...
通过 Taotoken CLI 工具一键配置开发环境中的多模型访问密钥
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 通过 Taotoken CLI 工具一键配置开发环境中的多模型访问密钥 在接入多个大模型服务时,开发者通常需要为不同的工具&…...
Head Activator ;pPPGGSKVILF
一、基础信息多肽名称:头部激活因子三字母序列:Pyr-Pro-Pro-Gly-Gly-Ser-Lys-Val-Ile-Leu-Phe单字母序列:pPPGGSKVILF氨基酸数量:11 aa分子式:C54H84N12O14分子量:1125.34结构特征:N 端 Pyr&…...
红外图像/红外遥感图像/可见光红外图像对 近红外和可见光成对图像 生成对抗网络的风格迁移,或者图像融合/图像生成/图像转换 可见光遥感生成红外遥感图像,37500对图像数据
红外图像/红外遥感图像/可见光红外图像对 近红外和可见光成对图像 生成对抗网络的风格迁移,或者图像融合/图像生成/图像转换 可见光遥感生成红外遥感图像,37500对图像数据 文章目录**数据集描述:**🧾 项目背景🧰 一、环…...
