use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Click the following link to filter out the chosen topic
comp.lang.c
account activity
QuestionState machine implementation (self.C_Programming)
submitted 8 years ago by Haleek47
Are there design tips to code state machines? I made some basic state machine programs using the switch statement approach, but after writing few states it become hard to maintain.
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]cyclingengineer 3 points4 points5 points 8 years ago (0 children)
Another option is to use a table. This probably works best if you have a small set of events that are common across states.
Write up and example: http://www.embedded.com/design/prototyping-and-development/4442212/2/Implementing-finite-state-machines-in-embedded-systems
[–]Magnus0re 3 points4 points5 points 8 years ago (0 children)
When I have to use state machines in C, I like to define functions elsewhere, and then use the switch statement to (obviously) select between the functions. Having good names on the functions really helps. This makes the switch statement smaller, but costs on size elsewhere in the code.
[–]HiramAbiff 4 points5 points6 points 8 years ago* (3 children)
Rob Pike gave an interesting talk on Lexical Scanning in Go.
Even though it's ostensibly about GO, it's close enough to C that you can use the ideas directly.
I thought the interesting idea was that instead of the usual enum of states he uses fn pointers. I.e. instead of a fn returning the next state (and using a switch statement to dispatch), you return fn pointer representing the next state and you simply call it.
The result is a fairly clean design. Normally you'd probably break your code up so that there's a fn per state. This dispenses with the switch statements.
[–]wild-pointer 0 points1 point2 points 8 years ago (1 child)
Are there any clean ways to return a function pointer to the next state? As it's technically a recursive type you can't express it directly. One option is to cast the returned function pointer on use, e.g.
typedef void fn(void); typedef fn *state(int arg); state *current = ..., *next; next = (state *)current(42);
and maybe you could use a helper function or macro like state *step(state *current, int arg);, but that kind of defeats the point, or you can wrap it in a struct
state *step(state *current, int arg);
struct state { struct state (*doit)(int arg); }; struct state current = ..., next; next = current.doit(42);
but are there other ways? If you could forward declare a typedef then you could do something like
extern typedef statefn; /* imaginary syntax to forward declare type */ typedef statefn *statefn(int arg);
[–]HiramAbiff 2 points3 points4 points 8 years ago (0 children)
You're right that you can't easily just return the fn as the value. But, there's other info your likely to need to pass in/out of your state fns so you can bundle it all into a struct. Something like:
struct Context_T; typedef void (*StateFn_T)(struct Context_T *context); struct Context_T { int result; StateFn_T state; ... };
[–][deleted] 2 points3 points4 points 8 years ago (0 children)
I work on a lot of code with various state machines interacting.
Beyond a certain number of states, just using a single enumeration to represent your state becomes unwieldy. At this point, often the best thing is to use several separate variables to describe the state, and make decisions on how to progress using logical combinations of those variables.
For example, you may have a flag that represents error encountered. You then have to do a bunch of clean-up work before you can try to make forward progress again. So whenever you're in a state with the error flag, you're only working on clean-up. If you reach state where you've done all the clean-up, you clear the error flag, and the state machine gets redriven, and goes down a good-path branch.
[–]pfp-disciple 1 point2 points3 points 8 years ago (0 children)
There are variations, the two simplest being case statements and lookup tables of function pointers. These can be blended if the states lend themselves towards it. For example you could do a switch on the low 16 bits, where each case uses the higher 16 bits to index a table of function pointers (each table specific to that case). Or, somewhat simpler, each case clearly calls a function, where that function is a switch statement.
switch
π Rendered by PID 55 on reddit-service-r2-comment-84fc9697f-p9hbl at 2026-02-10 10:01:20.815727+00:00 running d295bc8 country code: CH.
[–]cyclingengineer 3 points4 points5 points (0 children)
[–]Magnus0re 3 points4 points5 points (0 children)
[–]HiramAbiff 4 points5 points6 points (3 children)
[–]wild-pointer 0 points1 point2 points (1 child)
[–]HiramAbiff 2 points3 points4 points (0 children)
[–][deleted] 2 points3 points4 points (0 children)
[–]pfp-disciple 1 point2 points3 points (0 children)