我们需要在C秒内实现一个简单的状态机


switch(state)
{
  case STATE_1:
     state = DoState1(transition);
     break;
  case STATE_2:
     state = DoState2(transition);
     break;
}
...
DoState2(int transition)
{
   // Do State Work
   ...
   if(transition == FROM_STATE_2) {
     // New state when doing STATE 2 -> STATE 2
   }
   if(transition == FROM_STATE_1) {
    // New State when moving STATE 1 -> STATE 2
   }
   return new_state;
}

有更好的方法吗

编辑: 对于C++,我认为Boost Statechart库可能是可行的.但是,它对C有not个帮助.让我们集中在C用例上.

推荐答案

对于大多数状态机,我更喜欢使用表驱动的方法:

typedef enum { STATE_INITIAL, STATE_FOO, STATE_BAR, NUM_STATES } state_t;
typedef struct instance_data instance_data_t;
typedef state_t state_func_t( instance_data_t *data );

state_t do_state_initial( instance_data_t *data );
state_t do_state_foo( instance_data_t *data );
state_t do_state_bar( instance_data_t *data );

state_func_t* const state_table[ NUM_STATES ] = {
    do_state_initial, do_state_foo, do_state_bar
};

state_t run_state( state_t cur_state, instance_data_t *data ) {
    return state_table[ cur_state ]( data );
};

int main( void ) {
    state_t cur_state = STATE_INITIAL;
    instance_data_t data;

    while ( 1 ) {
        cur_state = run_state( cur_state, &data );

        // do other program logic, run other state machines, etc
    }
}

当然,这可以扩展到支持多状态机等.也可以适应转换操作:

typedef void transition_func_t( instance_data_t *data );

void do_initial_to_foo( instance_data_t *data );
void do_foo_to_bar( instance_data_t *data );
void do_bar_to_initial( instance_data_t *data );
void do_bar_to_foo( instance_data_t *data );
void do_bar_to_bar( instance_data_t *data );

transition_func_t * const transition_table[ NUM_STATES ][ NUM_STATES ] = {
    { NULL,              do_initial_to_foo, NULL },
    { NULL,              NULL,              do_foo_to_bar },
    { do_bar_to_initial, do_bar_to_foo,     do_bar_to_bar }
};

state_t run_state( state_t cur_state, instance_data_t *data ) {
    state_t new_state = state_table[ cur_state ]( data );
    transition_func_t *transition =
               transition_table[ cur_state ][ new_state ];

    if ( transition ) {
        transition( data );
    }

    return new_state;
};

表驱动方法更易于维护和扩展,并且更易于映射到状态图.

C++相关问答推荐

数组元素的编号索引

为什么海湾合作委员会在共享对象中的. init_data的虚拟内存地址之前留出一个空白

常数函数指针优化

单指针和空参数列表之间的函数指针兼容性

为什么在C中二维字符数组会有这样的行为?

两个连续的语句是否按顺序排列?

C:二进制搜索和二进制插入

核心转储文件中出现奇怪的大小变化

测量ARM MCU中断延迟的问题

Tic-tac-toe:从文件加载存储

如何在c中使用具有不同变量类型的内存分配?

如何组合两个宏来初始化C语言中的字符串数组?

基于蝶数恰好有8个除数的事实的代码

Dlsym()的手册页解决方法仍然容易出错?

C中的空指针是什么(_N)?

为什么GCC不能在 struct 初始值设定项中以sizeof作为条件的三进制中处理复合文字的编译时求值?

If语句默认为true

中位数和众数不正确

如何找出C中分配在堆上的数组的大小?

在 C/C++ 中原子按位与字节的最佳方法?