C中的状态机

Mau*_*lli 16 c state-machine

在C中编写状态机的最佳方法是什么?
我通常在for(;;)中编写一个大的switch-case语句,并在外部操作完成时使用回调来重新进入状态机.
你知道更有效的方式吗?

squ*_*art 26

我喜欢Quantum Leaps方法.

当前状态是指向将事件对象作为参数的函数的指针.当事件发生时,只需使用该事件调用state函数; 然后,该函数可以通过将状态设置为另一个函数来完成其工作并转换到另一个状态.

例如:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

QL框架为诸如入口/出口/初始化操作,分层状态机等额外事物提供帮助.我强烈推荐本书以便更深入地解释和良好实现.

  • 非常好,但你能把这些E _*变成'typedef enum'吗?(参见:http://stackoverflow.com/a/1102556/588561)这可以利用C类型检查(不可否认,并不多)来捕获更多错误.这在混合多个状态机时尤其重要,其中从一台机器到另一台机器的简单重用事件名称可能具有非常奇怪,难以调试的后果. (3认同)
  • @Multisync:我的一个更正:您可能希望考虑使用带有枚举的结构,而不是typedef,请参阅http://stackoverflow.com/q/8597426/588561以获取解释.使用`struct A_state {enum A_state st; }; struct B_state {enum B_state st; 在同一个应用程序中处理多个状态机时,等等有帮助,这可以防止您意外地将一个状态机的事件与另一个状态机的事件混合,因为结构是不同的,不兼容的类型.当然,您也可以在相应的结构中存储与机器相关的其他状态变量. (3认同)

bob*_*mcr 6

最好的方法主要是主观的,但常用的方法是使用"基于表格"的方法,将状态代码(枚举或其他整数类型)映射到函数指针.该函数返回您的下一个状态和其他相关数据,然后循环执行此操作,直到达到终端状态.事实上,这可能就是您所描述的上述方法.