当前位置: 首页 > news >正文

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语言实现状态机

关于状态机&#xff0c;基础的知识点可以自行理解&#xff0c;讲解的很多&#xff0c;这里主要是想写一个有限状态机FSM通用的写法&#xff0c;目的在于更好理解&#xff0c;移植&#xff0c;节省代码阅读与调试时间&#xff0c;体现出编程之美。 传统的实现方案 if...else : …...

交叉编译工具链arm-linux-gnueabihf的安装-ubuntu 20.04

前面下载安装步骤参考该博主的文章 http://t.csdn.cn/ZbjFX 另&#xff1a;本人对所遇到的环境变量的配置问题作补充 1.修改环境变量 建议直接在.bashrc文件作修改 &#xff0c;修改方式相同 ( vi :视自己的编辑器而定) sudo vi ~/.bashrc 2.修改环境变量后&#xff0c;可…...

Java的类加载器

类加载 1、ClassLoader 用来加载 Class 文件 2、 系统内置的ClassLoader 通过双亲委托加载指定目录下的class和资源 3、 可以自定义ClassLoader 一般覆盖findClass() 4、ContextClassLoader 与线程相关&#xff0c;可以获取和设置&#xff0c;可以绕过双亲委托的机制。 三个类…...

Stable Diffusion web UI 部署详细教程

前言 本文使用 AutoDL 平台进行 Stable Diffusion web UI 云端部署 AutoDL 官网&#xff1a;AutoDL算力云 | 弹性、好用、省钱。租GPU就上AutoDL Stable Diffusion web UI 官网&#xff1a;AUTOMATIC1111/stable-diffusion-webui: Stable Diffusion web UI (github.com) 步…...

《深度学习计算机视觉 》书籍分享(包邮送书三本)

深度学习计算机视觉介绍 随着计算机技术的发展和进步&#xff0c;计算机视觉领域得到了广泛的关注和研究。而深度学习作为一种强大的机器学习方法&#xff0c;已经成为计算机视觉领域的重要工具之一。本文将介绍深度学习在计算机视觉中的应用和取得的成果。 深度学习是一种模…...

【使用 k 折叠交叉验证的卷积神经网络(CNN)】基于卷积神经网络的无特征EMG模式识别研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

微服务 Nacos配置热部署

在nacos中添加配置文件 在配置列表中添加配置&#xff0c; 注意&#xff1a;项目的核心配置&#xff0c;需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。 从微服务拉取配置 微服务要拉取nacos中管理的配置&#xff0c;并且与…...

国产调度器之光——Fsched到底有多能打?

这是一篇推荐我们速石自研调度器——Fsched的文章。 看起来在专门写调度器&#xff0c;但又不完全在写。 往下看&#xff0c;你就懂了。 本篇一共五个章节&#xff1a; 一、介绍一下主角——速石自研调度器Fsched 二、只要有个调度器&#xff0c;就够了吗&#xff1f; 三…...

LeetCode:53. 最大子数组和 - Python

53. 最大子数组和 问题描述&#xff1a; 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 1&#xff1a; 输入&#xff1a;nums [-…...

网站建设 之 react usestate

react着重在于“不可变动” 如果变动了怎么办呢&#xff1f;那就整个新的 局部变量/函数/jsx-》state/props-〉ref&#xff0c;依次越来越难变 每次state/props&#xff0c;局部变量/函数/jsx都是新的 既然函数是新的&#xff0c;那么就会有一个问题&#xff0c;回调函数用…...

第一讲使用IDEA创建Java工程——HelloWorld

一、前言导读 为了能够让初学者更快上手Java,不会像其他书籍或者视频一样,介绍一大堆历史背景,默认大家已经知道Java这么编程语言了。本专栏只会讲解干货,直接从HelloWord入手,慢慢由浅入深,讲个各个知识点,这些知识点也是目前工作中项目使用的,而不是讲一些老的知识点…...

BootstrapBlazor组件使用:数据注解

文章目录 前言BB数据注解数据注解源码数据注解简介注解简单实例[BB 编辑弹窗](https://www.blazor.zone/edit-dialog)[ValidateForm 表单组件](https://www.blazor.zone/validate-form)使用简介 前言 BootstrapBlazor(一下简称BB)是个特别好用的组件&#xff0c;基本上满足了大…...

MySQL 触发器

文章目录 1.简介2.行级与语句级触发器3.触发时机4.触发器优缺点5.创建触发器语法示例 6.查看触发器7.删除触发器参考文献 1.简介 触发器&#xff08;Trigger&#xff09;是与表关联的命名数据库对象&#xff0c;当表发生特定事件时激活。 触发器的一些用途是对要插入表中的值执…...

DPDK主从进程模式 rte_mempool_put失败

版本&#xff1a;19.11.6 情景&#xff1a;主进程应用rte_mempool_create创建mempool&#xff0c;rte_mempool_get获取数据&#xff1b;从进程应用rte_mempool_put归还数据 问题&#xff1a;从进程rte_mempool_put无法归还数据 原因&#xff1a;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&#xff0c;32个16进制字符&#xff0c;占用存储空…...

Qt安卓开发经验技巧总结V202308

01&#xff1a;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&#xff01;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 注释单行注释多行注释注释的作用 四、 …...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...