Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I also have used the table approach. However, there is overhead. Why store a second list of pointers? A function in C without the () is a const pointer. So you can do:</p> <pre><code>struct state; typedef void (*state_func_t)( struct state* ); typedef struct state { state_func_t function; // other stateful data } state_t; void do_state_initial( state_t* ); void do_state_foo( state_t* ); void do_state_bar( state_t* ); void run_state( state_t* i ) { i-&gt;function(i); }; int main( void ) { state_t state = { do_state_initial }; while ( 1 ) { run_state( state ); // do other program logic, run other state machines, etc } } </code></pre> <p>Of course depending on your fear factor (i.e. safety vs speed) you may want to check for valid pointers. For state machines larger than three or so states, the approach above should be less instructions than an equivalent switch or table approach. You could even macro-ize as:</p> <pre><code>#define RUN_STATE(state_ptr_) ((state_ptr_)-&gt;function(state_ptr_)) </code></pre> <p>Also, I feel from the OP's example, that there is a simplification that should be done when thinking about / designing a state machine. I don't thing the transitioning state should be used for logic. Each state function should be able to perform its given role without explicit knowledge of past state(s). Basically you design for how to transition from the state you are in to another state.</p> <p>Finally, don't start the design of a state machine based on "functional" boundaries, use sub-functions for that. Instead divide the states based on when you will have to wait for something to happen before you can continue. This will help minimize the number of times you have to run the state machine before you get a result. This can be important when writing I/O functions, or interrupt handlers.</p> <p>Also, a few pros and cons of the classic switch statement:</p> <p>Pros:</p> <ul> <li>it is in the language, so it is documented and clear</li> <li>states are defined where they are called</li> <li>can execute multiple states in one function call</li> <li>code common to all states can be executed before and after the switch statement</li> </ul> <p>Cons:</p> <ul> <li>can execute multiple states in one function call</li> <li>code common to all states can be executed before and after the switch statement</li> <li>switch implementation can be slow</li> </ul> <p>Note the two attributes that are both pro and con. I think the switch allows the opportunity for too much sharing between states, and the interdependency between states can become unmanageable. However for a small number of states, it may be the most readable and maintainable. </p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload