views:

9077

answers:

14

We need to implement a simple state machine in C.
Is a standard switch statement the best way to go?
We have a current state (state) and a trigger for the transition.


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;
}

Is there a better way for simple state machines

EDIT: For C++, I think the Boost Statechart library might be the way to go. However, it does not help with C. Lets concentrate on the C use case.

A: 

Boost has the statechart library. http://www.boost.org/doc/libs/1_36_0/libs/statechart/doc/index.html

I can't speak to the use of it, though. Not used it myself (yet)

jdt141
+1  A: 

In my experience using the 'switch' statement is the standard way to handle multiple possible states. Although I am surpirsed that you are passing in a transition value to the per-state processing. I thought the whole point of a state machine was that each state performed a single action. Then the next action/input determines which new state to transition into. So I would have expected each state processing function to immediately perform whatever is fixed for entering state and then afterwards decide if transition is needed to another state.

Phil Wright
There are different underlying models: Mealy machines and Moore machines. Mealy's actions depend on the transition, Moore's ones depend on the state.
xmjx
+1  A: 

In C++, consider the State pattern.

Bruno De Fraine
I'm wondering if there's a way to mimic the state pattern in C...
Thomas Owens
+3  A: 

there is also the logic grid which is more maintainable as the state machine gets bigger

geocoin
+2  A: 

For simple cases, you can you your switch style method. What I have found that works well in the past is to deal with transitions too:

static int current_state;    // should always hold current state -- and probably be an enum or something

void state_leave(int new_state) {
    // do processing on what it means to enter the new state
    // which might be dependent on the current state
}

void state_enter(int new_state) {
    // do processing on what is means to leave the current atate
    // might be dependent on the new state

    current_state = new_state;
}

void state_process() {
    // switch statement to handle current state
}

I don't know anything about the boost library, but this type of approach is dead simple, doesn't require any external dependencies, and is easy to implement.

Mark
+2  A: 

The state pattern as previously state :

[http://www.codeproject.com/Kb/architecture/StatePatternBy_Sarath._.aspx][1]

I you can put your hands on the book "head first design pattern", the explanation and example are very clear.

pmlarocque
A: 

There is a book titled Practical Statecharts in C/C++. However, it is way too heavyweight for what we need.

Benoit
Dan
+21  A: 

I prefer to use a table driven approach for most state machines:

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
    }
}

This can of course be extended to support multiple state machines, etc. Transition actions can be accommodated as well:

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;
};

The table driven approach is easier to maintain and extend and simpler to map to state diagrams.

Frank Szczerba
Very nice way to get started, at least beginning point for me. One remark, the first line of run_state() has a naughty "." that shouldn't be there.
Atilla Filiz
+5  A: 

You might have seen my answer to another C question where I mentioned FSM! Here is how I do it:

FSM {
  STATE(x) {
    ...
    NEXTSTATE(y);
  }

  STATE(y) {
    ...
    if (x == 0) 
      NEXTSTATE(y);
    else 
      NEXTSTATE(x);
  }
}

With the following macros defined

#define FSM
#define STATE(x)      s_##x :
#define NEXTSTATE(x)  goto s_##x

This can be modified to suit the specific case. For example, you may have a file FSMFILE that you want to drive your FSM, so you could incorporate the action of reading next char into the the macro itself:

#define FSM
#define STATE(x)         s_##x : FSMCHR = fgetc(FSMFILE); sn_##x :
#define NEXTSTATE(x)     goto s_##x
#define NEXTSTATE_NR(x)  goto sn_##x

now you have two types of transitions: one goes to a state and read a new character, the other goes to a state without consuming any input.

You can also automate the handling of EOF with something like:

#define STATE(x)  s_##x  : if ((FSMCHR = fgetc(FSMFILE) == EOF)\
                             goto sx_endfsm;\
                  sn_##x :

#define ENDFSM    sx_endfsm:

The good thing of this approach is that you can directly translate a state diagram you draw into working code and, conversely, you can easily draw a state diagram from the code.

In other techniques for implementing FSM the structure of the transitions is buried in control structures (while, if, switch ...) and controlled by variables value (tipically a state variable) and it may be a complex task to relate the nice diagram to a convoluted code.

I learned this technique from an article appeared on the great "Computer Language" magazine that, unfortunately, is no longer published.

Remo.D
Fundamentally, a good FSM is all about readability. This provides a good interface, and the implementation is as good as it gets. It is a shame that there isn't a native FSM structure in the language. I can see it now as a late addition to C1X!
Kelden Cowan
+1  A: 

Also consider the work of Miro Samek and his website.

kenny
+2  A: 

For a simple state machine just use a switch statement and an enum type for your state. Do your transitions inside the switch statement based on your input. In a real program you would obviously change the "if(input)" to check for your transition points. Hope this helps.

typedef enum
{
    STATE_1 = 0,
    STATE_2,
    STATE_3
} my_state_t;

my_state_t state = STATE_1;

void foo(char input)
{
    ...
    switch(state)
    {
     case STATE_1:
      if(input)
       state = STATE_2;
      break;
     case STATE_2:
      if(input)
       state = STATE_3;
      else
       state = STATE_1;
      break;
     case STATE_3:
      ...
      break;
    }
    ...
}
jsl4980
Might be worth putting "state" inside the function, and making it static.
Steve Melnikoff
@Steve Melnikoff: only if you've only got one state machine. Keep it outside the function and you can have an array of state machines with their own state.
Vicky
@Vicky: One function can contain as many state machines as you like, with an array of state variables if required, which can live inside the function (as static variables) if they're not used elsewhere.
Steve Melnikoff
+1  A: 

switch() is a powerful and standard way of implementing state machines in C, but it can decrease maintainability down if you have a large number of states. Another common method is to use function pointers to store the next state. This simple example implements a set/reset flip-flop:

/* Implement each state as a function with the same prototype */
void state_one(int set, int reset);
void state_two(int set, int reset);

/* Store a pointer to the next state */
void (*next_state)(int set, int reset) = state_one;

/* Users should call next_state(set, reset). This could
   also be wrapped by a real function that validated input
   and dealt with output rather than calling the function
   pointer directly. */

/* State one transitions to state one if set is true */
void state_one(int set, int reset) {
    if(set)
        next_state = state_two;
}

/* State two transitions to state one if reset is true */
void state_two(int set, int reset) {
    if(reset)
        next_state = state_one;
}
Commodore Jaeger
+1  A: 

You might want to look into the libero FSM generator software. From a state description language and/or a (windows) state diagram editor you may generate code for C, C++, java and many others ... plus nice documentation and diagrams. Source and binaries from iMatix

pklausner
A: 

Your question is similar to "is there a typical Data Base implementation pattern"? The answer depends upon what do you want to achieve? If you want to implement a larger deterministic state machine you may use a model and a state machine generator. Examples can be viewed at www.StateSoft.org - SM Gallery. Janusz Dobrowolski

Janusz Dobrowolski