用C编写状态机的最佳方法是什么?

我通常在for(;;)中编写一个大的switch-case语句,并使用回调在外部操作完成后重新进入状态机。

您知道更有效的方法吗?

这似乎是一种非常标准的实现方法。

嘿! 听起来就像我在做什么。 小世界。

嘿! 您偷了我的代码并复制了!

请参阅我对stackoverflow.com/questions/1371460/state-machines-tutorials的回答-我认为表驱动的方法(从代码维护和可读性的角度来看)比一个大的开关更有效。

Ive在这里还发布了一些宏魔术:stackoverflow.com/questions/1647631/c-state-machine-design/

是否存在典型的状态机实施模式?

我喜欢Quantum Leaps方法。

当前状态是指向以事件对象作为参数的函数的指针。当事件发生时,只需使用该事件调用状态函数即可;然后,只需将状态设置为另一个功能即可执行其工作并转换到另一个状态。

例如。:

// State type and variable, notice that it's a function pointer.

typedef void (*State)(int);

State state;

// A couple of state functions.

void state_xyz(int event) { /*...*/ }

void state_init(int event) {

if (event == E_GO_TO_xyz) {

// State transition done simply by changing the state to another function.

state = state_xyz;

}

}

// main contains the event loop here:

int main() {

int e;

// Initial state.

state = state_init;

// Receive event, dispatch it, repeat... No 'switch'!

while ((e = wait_for_event()) != E_END) {

state(e);

}

return 0;

}

QL框架为其他事情提供了帮助,例如进入/退出/初始化动作,分层状态机等。我强烈建议该书以提供更深入的说明和良好的实现。

我用AI做的,很好的方法

那有多快?

此方法消除了一个级别的开关或表查找,因为状态是您刚刚调用的函数的直接指针。但是,像往常一样,只有通过测试才能确保实际速度提高!它也应该有助于维护,这在足够大的项目中可能很重要。

非常好,但是您可以将这些E_ *转换为typedef enum吗? (请参阅:stackoverflow.com/a/1102556/588561)这可以利用类型检查C所具有的(公认的,数量不多)来捕获更多错误。这在混合多个状态机时尤其重要,在这种状态机中,事件名称从一台计算机到另一台计算机的简单重用可能会产生非常奇怪且难以调试的后果。

@ack:不幸的是我还不明白,您能详细说明使用typedef有什么好处吗?如何捕获错误,否则将无法捕获?

@Multisync:我的更正:您可能不希望使用带有枚举的结构,而不是typedef,请参见stackoverflow.com/q/8597426/588561以获取解释。使用struct A_state { enum A_state st; }; struct B_state { enum B_state st; }等有助于在同一应用程序中处理多个状态机,这可以防止您意外地将一个状态机的事件与另一个状态机的事件混合,因为结构是不同的,不兼容的类型。当然,您也可以在相应的结构中存储与机器相关的其他状态变量。

最好的方法在很大程度上是主观的,但是一种常见的方法是使用"基于表"的方法,其中将状态代码(枚举或其他整数类型)映射到函数指针。该函数返回您的下一个状态和其他关联的数据,并循环浏览直到达到终端状态。实际上,这可能就是您在上面描述的方法。

这几乎是标准方法。如果您有兴趣研究经过深思熟虑的库并比较具体特征,请查看Ragel:

Ragel compiles executable finite state machines from regular languages. Ragel targets C, C++, Objective-C, D, Java and Ruby. Ragel state machines can not only recognize byte sequences as regular expression machines do, but can also execute code at arbitrary points in the recognition of a regular language. Code embedding is done using inline operators that do not disrupt the regular language syntax.

switch语句是入门的好方法,但是当FSM变大时,它们往往变得笨拙。

几个相关的(或重复的)SO问题具有很好的信息和想法:

状态机教程

C状态机设计

我使用了这种模式。有没有典型的状态机实施模式? (检查最佳答案)。

但是我还添加了一些功能

1.有关先前状态的信息。

2.参数传递

3.添加外部事件,例如全局超时和"重置SM"

我发现状态机的神秘性和可维护性要少一些。

无论如何,我仍然认为状态机是最困难且烦人的编程任务。(到目前为止)

另一种方法是2D数组,它为每个状态/事件组合描述要执行的动作以及要进入的下一个状态。当您需要根据"情况"转换到不同的状态时,这可能会变得更加棘手,但是可以使其正常工作。您有一个事件识别器函数,该函数返回下一个事件。您拥有该表,该表中的每个条目都标识了接收事件时要调用的函数以及要进入的下一个状态-除非被调用函数覆盖该状态。

实际上生成这样的代码比较麻烦-它首先取决于如何描述FSM。发现重复动作通常很重要。通常,您可以依靠"稀疏矩阵"技术,这些技术不会显式记录错误处理:如果条目逻辑上存在于稀疏矩阵中,那么您将对该事件/状态信息进行操作,但是如果该条目不存在,则会退回到适当的位置错误报告和重新同步代码。

可以将指向结构的2D指针数组传递给通用FSM函数。您编写三重指针这一事实足以使您对正在发生的事情保持谨慎。 (我在1986年3月写过一篇文章-尽管磁盘上仍然没有描述它的文档,但我在磁盘上再也没有该源了。)

您可以使用在c中实现的最低限度的uml状态机框架。 它支持有限状态机和分层状态机。 该框架非常简约。 它只有3个API,2个结构和1个枚举。

状态机由state_machine_t结构表示。 它是可以继承以创建状态机的抽象结构。

//! Abstract state machine structure

struct state_machine_t

{

uint32_t Event;          //!< Pending Event for state machine

const state_t* State;    //!< State of state machine.

};

状态由指向框架中state_t结构的指针表示。

如果框架是为有限状态机配置的,则state_t包含,

typedef struct finite_state_t state_t;

// finite state structure

typedef struct finite_state_t{

state_handler Handler;        //!< State handler function (function pointer)

state_handler Entry;          //!< Entry action for state (function pointer)

state_handler Exit;           //!< Exit action for state (function pointer)

}finite_state_t;

如果框架配置为支持分层状态机。 它包含其他三个成员,以表示状态之间的层次关系。

typedef struct hierarchical_state_t state_t;

//! Hierarchical state structure

typedef struct hierarchical_state_t

{

state_handler Handler;      //!< State handler function

state_handler Entry;        //!< Entry action for state

state_handler Exit;         //!< Exit action for state.

const state_t* const Parent;    //!< Parent state of the current state.

const state_t* const Node;      //!< Child states of the current state.

uint32_t Level;                 //!< Hierarchy level from the top state.

}hierarchical_state_t;

该框架提供了一个API dispatch_event来将事件分发到状态机,并提供了两个用于状态遍历的API。

state_machine_result_t dispatch_event(state_machine_t* const pState_Machine[], uint32_t quantity);

state_machine_result_t switch_state(state_machine_t* const pState_Machine, const state_t* pTarget_State);

state_machine_result_t traverse_state(state_machine_t* const pState_Machine, const state_t* pTarget_State);

有关更多详细信息,请参阅GitHub项目。

我使用函数指针和2D查找表,其中将状态用于一个参数,将事件用作另一个。

我使用excel(或任何电子表格工具)将功能映射到每个状态/事件组合。

发生事件时,我会对其进行排队,然后我得到的东西看起来像这样

int main(void)

{

StateList currentState = start_up;

EventList currentEvent;

uint8_t stateArray[STATE_COUNT][EVENT_COUNT];

InitializeStateArray(stateArray);

InitializeEventQue();

while(1)

{

currentEvent = GetPriorityEvent();

currentState = (StateList)(*(stateArray[currentState][currentEvent]))();

}

return 1;  //should never get here

}

从本质上讲,该方法迫使开发人员考虑每种状态下的所有可能事件,并且根据我的经验,调试变得更加容易。

在这里看看:http://code.google.com/p/fwprofile/

这是状态机的开源版本(GNU GPLv3)

该概念和实现非常适合用于

关键任务应用程序。在工业中有部署

应用。

c语言中状态机的作用,C语言中的状态机相关推荐

  1. c语言程序中cost的作用,C语言考试题基础版(21页)-原创力文档

    if (x>y)z=x; s=z*z;elsez=y;s=1/(z*z); if (x>y) z=x; s=z*z; else z=y;s=1/(z*z); 7. B. C. PAd, P ...

  2. c语言在中职的作用,C语言程序下的中职教学论文

    一.树立学生良好的学习信心 在日常的中职计算机教育教学中,应当重视学生对教学内容的看法,大多数学生认为C语言学习相对较为困难,在日常的中职计算机学习中,学生某种程度上缺乏应有的信心以及勇气,而尽管有的 ...

  3. C语言switch中break的作用,C语言switch中break语句的作用

    问题: break在for循环.while循环等循环流程控制中起的作用是停止执行break后面的语句,跳出本次循环,并跳出该循环控制体: 在switch条件选择中,没有了循环控制,break又起什么作 ...

  4. c语言程序头文件作用,C语言头文件

    C语言头文件教程 C 语言的头文件一般都是 .h 做为结尾的. C语言头文件详解 语法 #include 参数 参数 描述 filename 我们需要引入的头文件的名称. 说明 C 语言的头文件一般都 ...

  5. c语言对编程对作用,c语言编程心得体会

    c语言编程心得体会 c语言是在国内外广泛使用的一种计算机语言.以下是小编整理的c语言编程心得体会,欢迎大家阅读! c语言编程心得体会1 说到我学习c语言时,真是用千言万语呀!记得刚开始学的时候,我的c ...

  6. c语言的应用与作用,C语言主要应用在什么地方?

    C语言是一种计算机程序设计语言.它既有高级语言的特点,又具有汇编语言的特点.它可以作为系统设计语言,编写工作系统应用程序,也可以作为应用程序设计语言,编写不依赖计算机硬件的应用程序.因此,它的应用范围 ...

  7. c语言eof不起作用,c语言程序设计 怎么以输入EOF结束

    EOF(EndOfFile)是C语言中的文件结束标志符.当C语言输入函数获取到文件结尾标志时,会通过返回值的方式体现该值.所以要以输入EOF为结束,就需要判断输入函数的返回值.EOF定义在stdio. ...

  8. c语言链表head的作用,c语言链表的用法

    c语言链表的用法 链表是数据结构中比较基础也是比较重要的类型之一,那么有了数组,为什么我们还需要链表呢!或者说设计链表这种数据结构的初衷在哪里?下面小编就为大家介绍下c语言链表的用法. c语言枚举的用 ...

  9. c语言(cn)括号的作用,c语言小括号的用法

    c语言小括号的用法 C语言的小括号里面表示一条语句,返回值是多条语句中最靠右的语句的返回值,比如(a=2,b=3,c=a+b),返回值就是c的值.下面小编就为大家介绍c语言小括号的用法. c语言小括号 ...

  10. c语言位与运算的作用,c语言位运算符的用法

    c语言位运算符的用法 C语言中位运算的运算分量只能是整型或字符型数据,位运算把运算对象看作是由二进位组成的位串信息,按位完成指定的运算,得到位串信息的结果.下面小编就为大家介绍下c语言位运算符的用法. ...

最新文章

  1. gps两点距离 php,PHP应用:PHP计算百度地图两个GPS坐标之间距离的方法
  2. PLSQL_性能优化系列04_Oracle Optimizer优化器
  3. Linux服务器安装NodeJs简易方法
  4. 修饰符(public/private/default/protected)
  5. 手机长曝光怎么设置_摄影教程丨手机如何拍摄长曝光照片,流光快门,星空银河搞起来!...
  6. abd.exe 需要下java吗_abd.exe
  7. java环境变量配置失败_java环境变量配置失败是怎么回事?出错解决办法分享
  8. ActiveMQ菜鸟入门教程
  9. Sougou微信文章获取
  10. Java Web基础知识之文件上传:文件上传一窥究竟
  11. MainMenu.xib
  12. 常用国内镜像源地址汇总
  13. 澳门大学计算机qs排名,澳门大学世界QS排名
  14. P1978 集合 (set)
  15. python10086查询系统_Python数字移动设备取证
  16. 阶乘因式分解(一)/java
  17. 数控车椭圆编程实例带图_数控车床加工椭圆的宏程序实例
  18. PHP快速入门(一)
  19. 本地回环地址127.0.0.1
  20. python实现录音并去燥_Python | 简单的扩音,音频去噪,静音剪切

热门文章

  1. 微信小程序API之showModal(Loding...)
  2. JavaScript获取当前月的第一天和最后一天日期
  3. Opencv之以亚像素精度获取图片的ROI--cv.getRectSubPix
  4. docker下搭建JupyterNotebook远程登录
  5. sql中去掉字段的所有空格
  6. ORACLE常用监控语句(未完待续)
  7. 代码行云流水..这位刚高中毕业的 UP 主,告诉我人的学习能力没有上限
  8. 【李宏毅2020 ML/DL】P75 Generative Adversarial Network | Conditional GAN
  9. 实验一 Linux开发环境的配置 20145213祁玮 20145222黄亚奇
  10. 【图】二分图最大权匹配