我一直在尝试使用C语言实现状态机而我不是 确定我的实施是否合适。我试图以伪对象的方式实现状态图。所以我在StateMachine.h头文件中声明了StateMachine“class”的公共接口:
typedef enum{
STATE_01,
STATE_02,
STATE_03,
STATE_04
}state_e;
typedef enum{
NO_EVENT,
EVENT_01,
EVENT_02,
EVENT_03,
EVENT_04,
EVENT_05,
EVENT_06,
EVENT_07
}event_e;
// state machine instance
typedef struct{
state_e currState;
}StateMachine;
extern void InitState(StateMachine*);
extern void ProcSTATE_01(StateMachine*, event_e);
extern void ProcSTATE_02(StateMachine*, event_e);
extern void ProcSTATE_03(StateMachine*, event_e);
extern void ProcSTATE_04(StateMachine*, event_e);
extern void ProcEvent(StateMachine*, event_e);
StateMachine对象“methods”的实现位于StateMachine.c模块中:
void InitState(StateMachine *sm)
{
sm->currState = STATE_01;
}
void ProcSTATE_01(StateMachine *sm, event_e event)
{
if(event == EVENT_01){
sm->currState = STATE_02;
}
}
void ProcSTATE_02(StateMachine *sm, event_e event)
{
// ...
}
void ProcSTATE_03(StateMachine *sm, event_e event)
{
// ...
}
void ProcSTATE_04(StateMachine *sm, event_e event)
{
// ...
}
void ProcEvent(StateMachine *sm, event_e event)
{
switch(sm->currState){
case STATE_01:
ProcSTATE_01(sm, event);
break;
case STATE_02:
ProcSTATE_02(sm, event);
break;
case STATE_03:
ProcSTATE_03(sm, event);
break;
case STATE_04:
ProcSTATE_04(sm, event);
break;
}
}
StateMachine对象的用法如下:
int main(int argc, char** argv) {
StateMachine app;
ProcEvent(&app, EVENT_01);
return 0;
}
我想问任何人更有经验的是他是否能看到与此实施相关的任何潜在问题。感谢您的任何意见。
答案 0 :(得分:1)
您需要考虑事件的来源。它们只是从状态转换处理程序本身生成,还是外生的。如果它们是外生的,那么您可能希望在处理程序外部有一个事件循环,它从队列中提取事件并将它们注入适当的处理程序(这可能会将另一个事件排入队列以供以后处理)。此外,您可能希望将状态事件处理函数存储在一个数组中(索引状态编号),以便您可以通过编程方式调用它们(而不必使用巨型switch语句)。
答案 1 :(得分:1)
没有实现状态机的“正确”方法(例如Doug提到的状态表方法),但是有一些代码可以使您直接了解什么易于使用和哪些不易使用。 Miro Samek有一本书关于在c / c ++中使用分层状态机。他在那里将不同的样式与他开发的状态机样式进行了比较。我必须说,他的风格对我来说是最合理和易读的。 该书的一部分也可以在state-machine.com上在线获得。 实际上,您的状态机框架与Miros方法的状态机部分非常相似,他的方法也增加了等级转换的可能性,每个状态机的队列,系统滴答机制,事件回收,零事件复制策略等。如果您查看他的网站,您会发现您的方法是一种很好的方法,可以通过很多很多方式进行扩展。