近来思绪有点停不下来,构思了一个GUI的框架(用在Cotex-M平台上,很小),期待以后有时间去实现,里面有一个对触摸屏的检测,自然想到使用状态机进行消息的生成和分发,于是想着实现一个状态机实现的模型,以后再其他项目上应用也方便。

状态机的好处不用多说,自己百度去,但传统的编程模式,无论是C语言,或是硬件FPGA的Verilog都是采用switch-case结构,硬件的还好说,是并行的,但如果是C语言实现状态机则可能需要对每个case进行判断,状态少比如几个可能没什么效率之类的问题,但状态多几十个上百个呢,那么就需要进行上百次的判断是否匹配,毫无疑问效率很低,切每次的状态切换时间也不确定。那么有没有一种好的实现模式不用switch-case结构呢?下面我来为C语言状态机的实现建立一个最优模式。

实现

前面说了一堆***i的废话,下面进入正题,前段时间研究了下函数式编程,发现C语言的循环结构完全可以用尾递归(不懂百度)实现,最后C就只剩下唯有if和switch还不能用函数式编程实现,而今天要讲的状态机模式就是用函数式编程实现switch-case,那么switch-case其实可以看做一种查找的跳转,我们知道C语言中goto可以实现跳转,那么还有什么可以实现跳转呢,答案是函数调用,但是又需要如何实现指定的函数调用呢,难道要用if判断,显然没什么意义,那么又没有比if判断(如果上百次判断)更高效的东西呢?有人已经想到是查表,如果将查表和函数调用结合,那么就是函数指针数组的应用了!

上代码!首先定义一个函数指针类型,为什么要带void *的参数后面会说:

typedef unsigned char State;

typedef State(*Procedure)(void *);

这样就可以方便地定义一个函数指针数组:

Procedure Steps[] = { step_init, step_count, step_done, step_default };

step_init,step_count等是函数名,再定义状态:

enum states{ s_init, s_count, s_done, s_default };

枚举定义对应着{0,1,2,3},有了这些再状态机联系那么可以想到,数组的索引就是状态定义,上核心代码,两行(简单吧!关键是想到):

void BestStateMachine(void * invar) { static State NS = s_init; //定义下一状态 NS = Steps[NS](invar); } static的变量NS在每次BestStateMachine调用会得到维护,我们只需再每Steps返回下一个状态并保存到NS中可以实现状态的保存和切换。再说说为什么要加个void*的参数,状态机一般有很多自身变量的维护,而且对于mealy状态机还需根据输入判断,因为函数调用返回是不保留局部变量的,那么就需要将变量传递来实现更改和保存,之所以只用了一个void*参数是因为,如果需要保存和传递的变量很多,直接传递会在调用函数是浪费大量的栈空间,且效率低下,采用这种模式,你可以将变量用一个结构体封装,然后将结构体指针传递给void *的形参,再函数内部再强制转换即可使用结构体内部的变量。现在你已经在嘀咕这作者真啰嗦,好上实例代码,就是一个简单的计数器(以前学状态机都从计数器开始),在计数完成打印信息:

#include typedef unsigned char State; typedef State(*Procedure)(void *); enum states{ s_init, s_count, s_done, s_default };//状态定义 typedef struct _SM_VAR //对状态机参数封装 { int cnt; }SM_VAR; State step_init(void * arg)//初始化 { SM_VAR *p = (SM_VAR *)arg; p->cnt = 0; printf("CS:init ;cnt=%d;NS:count\n", p->cnt); return s_count; } State step_count(void * arg)//计数 { SM_VAR *p = (SM_VAR *)arg; if (p->cnt < 3){ p->cnt+=1; printf("CS:count;cnt=%d;NS:count\n", p->cnt); return s_count; } else{ printf("CS:count;cnt=%d;NS:done\n", p->cnt); return s_done; } } State step_done(void * arg)//计数完成 { SM_VAR *p = (SM_VAR *)arg; printf("CS:done ;cnt=%d;NS:init\n", p->cnt); return s_init; } State step_default(void * arg)//错误过程 { SM_VAR *p = (SM_VAR *)arg; printf("Wrong State\n"); return s_init; } Procedure Steps[] = { step_init, step_count, step_done, step_default }; void BestStateMachine(void * invar) { static State NS = s_init; //定义下一状态 NS = Steps[NS](invar); } int main(void) { SM_VAR var; int i; for (i = 0; i <8; i++){//给状态机8个周期的时钟驱动 BestStateMachine(&var); } return 0; }

最后在VS2013上调试如下:

CS:init ;cnt=0;NS:count CS:count;cnt=1;NS:count CS:count;cnt=2;NS:count CS:count;cnt=3;NS:count CS:count;cnt=3;NS:done CS:done ;cnt=3;NS:init CS:init ;cnt=0;NS:count CS:count;cnt=1;NS:count 请按任意键继续. . .

总结

以这种模式不仅可以实现上面的Moore型状态机,还可根据实际实现Mealy型状态机,结构清晰易懂,在这里我敢说最优,是因为这是C函数式编程的极限了,如果你有更好的想法联系我,邮箱:869119842@qq.com,唐童鞋。如果你对嵌入式GUI感兴趣,我们可以一起探讨写出我们自己的GUI。

c语言状态机实现坐标切换,C语言状态机最优模式(转)相关推荐

  1. c语言实现gps坐标转化,C语言计算GPS卫星位置

    <C语言计算GPS卫星位置>由会员分享,可在线阅读,更多相关<C语言计算GPS卫星位置(8页珍藏版)>请在人人文库网上搜索. 1.C 语 言 计 算GPS卫星位置1 概述在用G ...

  2. c语言扫雷显示坐标周围,C语言实现扫雷 - osc_kas7094m的个人空间 - OSCHINA - 中文开源技术交流社区...

    实现用C语言编写一个扫雷游戏 大家想必都玩过扫雷,无论那个版本都有难度供已选择,下面来分享一个自己用C语言编写的扫雷游戏吧! 编写语言:C语言 编写软件:visual studio 2017 1.首先 ...

  3. Android 切换系统语言源码分析

    以前了解Android的多语言实现很简单,可以在不同的语言环境下使用不同的资源,就做好相应的语言适配就好,但是一直没有实际使用过. 最近公司的项目要用到多国语言切换,并且还是和手机上系统设置里面的语言 ...

  4. android 指定语言的资源,Android国际化多语言切换

    最近工作中突然要求要项目进行国际化,之前没遇到过.但是也很简单呀,只需要把添加一个相应语言的的strings.xml的资源文件就好了,不是吗?这样只要切换系统语言就能切换app的文字语言了. 但是由此 ...

  5. 傲游浏览器语言怎么切换 傲游浏览器语言切换方法简述

    作为一款多功能.个性化.多标签的浏览器产品,傲游浏览器不仅能够有效减少浏览器对系统资源的占用率,还内置了大量的贴心功能,其中便包括浏览器语言切换.那么,傲游浏览器语言要怎么切换呢?不清楚具体步骤的朋友 ...

  6. android 语音和输入法按钮切换,android 切换系统语言,输入法也随之切换

    为什么有时候切换系统语言,输入法也随之切换 在系统有谷歌拼音输入法(Pinying输入法)和android 键盘输入法(Latin 输入法)的时候,此时系统的输入法不是第三方输入法. 在这时候去切换系 ...

  7. Android APP切换系统语言

    1.需求 三方APP实现点击切换语言功能(类似于系统Settings中点击语言自动切换) 2.实现 2.1 跳转到系统Settings的语言选择界面,实现功能 跳转代码: Intent intent ...

  8. Android 获取当前系统语言和切换系统语言

    最近有需求需要切换系统语言的功能,查阅api最终搞定,代码分享如下: 1.切换语言 public void updateLanguage(Locale locale) {try {Object obj ...

  9. Android 切换系统语言

    切换系统语言分为下面两个步骤: 1. 创建不同语言资源: 2. 替换当前页面 Context 所持有的资源: 一.创建不同语言资源 创建步骤如下: 二.替换资源 界面需要重新创建,使用 recreat ...

最新文章

  1. Java的File类
  2. javascript 错误与调试
  3. springMVC3学习--ModelAndView对象(转)
  4. 【Vue2.0】—vue-router(二十六)
  5. Cisco IPSec *** 配置详解
  6. OmniGraffle 7 Pro全新推出!V7.18.3(204.9.0)正式版 支持M1
  7. 实用软件工程第二版吕云翔课后答案
  8. jieba分词工具的使用-python代码
  9. HTML基本语法格式(元素、标签)
  10. message计算机英语,计算机英语词汇解释汇总
  11. pdf分解成多个pdf?PDF分割怎么做
  12. mysql数据库用户名修改密码_如何修改mysql数据库中的用户名和密码
  13. java面试之自我介绍
  14. Android开发:一个TextView中设置文字不同字体大小和颜色的2种高效方法
  15. opencv将图像处理之后显示在label上(Mat转化为qimage)转换之后label显示全黑
  16. 关于如何将网页做的完整且美观的解决办法
  17. 4个字母的排列组合c语言,1,2,3,4四个数字有多少种排列组合,是怎样的
  18. 新生宝宝为何天生过敏体质 婴儿过敏体质的症状
  19. 远指针,近指针,巨指针
  20. Windows下的MS17-010(永恒之蓝)漏洞分析与复现

热门文章

  1. JS、Java、C 依然强势,Go、Kotlin、Python 成为潜力股,2020 开发者生态系统报告揭晓!...
  2. 诞生一年来,V 语言还好吗?
  3. DevOps 火爆,要学这么多技术!
  4. 挚同道合,物所不能!挚物·AIoT产业领袖峰会报名进入倒计时!
  5. 从事 Java 20 年最终却败给了 Python,哭了!
  6. 百年 IBM 如何用代码拯救生命
  7. 百万畅销书带你学 Python:第一个程序
  8. 因代码不规范,码农枪击4名同事,一人情况危急
  9. 靠社交和游戏两张牌,腾讯还能活多久? | 畅言
  10. 最流行的 IDE 之争:Eclipse 反超 Visual Studio 成第一