# Function pointer question

## Recommended Posts

sbayeta    122
Hi, I'm writing a little program targetting a microcontroller. It's somewhat a state machine, where the program is always looping throw a defined state until it founds that some condition changed and hence must go to a new state. These states are implemented as individual functions:
char stateA() {
for(;;) {
if(condition1) {
//do something
return 'B';  //go to state B
}
else if(condition2) {
//do something else
return 'D';  //go to state B
}
}
}

The main function initially sets the state and then enters an infinete loop switching between states:
main() {
char state = 'A';
for(;;) {
switch(state) {
case 'A':
state = stateA();
break;
case 'B':
state = stateB();
break;
case 'C':
state = stateB();
break;
case 'D':
state = stateD();
break;
}
}
}

This is working find, but it's not very comfortable to add new states because I need to touch a lot of code (the program is big, I have enums, constants, #defines, etc) So I think a nicer approach would be to make the states functions return a pointer to another state function instead of a char. The problem is I don't know how to declare such a pointer (I don't know if it is even possible) since the type of the function pointed to is the same as the type being defined. Can anyone tell me how can I do this, it is at all possible ? Thanks a lot

##### Share on other sites
eighty    220
I suppose you could return void* and cast the result back to a function when you want to use it, but a neater solution would probably be to use functors inheriting from an abstract base class State.

##### Share on other sites
snk_kid    1312
Quote:
 Original post by eightyI suppose you could return void* and cast the result back to a function when you want to use it, but a neater solution would probably be to use functors inheriting from an abstract base class State.

We don't even know if he might be using strick C here this is for a micro-controller, anyways if you are using C and not C++ first this web-site will tell all you need to know about function pointers here. And here is a little program that shows you how to return a the address of some function in strict C and you don't need to use a void pointer for this:

#include <stddef.h>#include <stdio.h>void func1() {  printf("hello func1\n");  }void func2() {   printf("hello func2\n");}typedef void (*state_func)();state_func state(size_t i) {      static const state_func array_of_funcs[] = { func1, func2 };   return array_of_funcs[i];}int main() {      state_func f = state(0);   (*f)();   f = state(1);   (*f)();   return 0;}

[Edited by - snk_kid on August 3, 2004 6:57:32 AM]

##### Share on other sites
if you're using plain C this will work
#include <stdio.h>#include <conio.h>typedef void* (state_t)(void);state_t init_state, run_state, exit_state;void* init_state(void){	puts("Hello and welcome!");	return run_state;}void* run_state(void){	do	{		puts("press 'q' to quit.");	}while(getch() != 'q');	return exit_state;}void* exit_state(void){	puts("doing cleanup");	return NULL;}int main(void){	state_t *state = init_state;	while( state) state = state();}

if you're using C++ you either have to do some casting or use functors or some other technique, it basicly boils down to what language you're using.

##### Share on other sites
petewood    819
Also see Robert Martin's State Machine Compiler and the similarly named smc on sourceforge

##### Share on other sites
sbayeta    122
OK, thanks a lot for those replies.

I forgot to mention I'm using an almost-ANSI C compiler (it doesn't support recursive calls and some other few features).

I will try the void* thing first, but I guess it won't work, since it is a Harvard arquitecture microcontroller.

Thanks again

##### Share on other sites
sbayeta    122
I think I miaght have found a solution. Let me know what you think about it.

struct statetag;typedef struct statetag(*state_func)();typedef struct statetag {	state_func execute;}state_t;state_t stateA();state_t stateB();state_t stateC();int main(int argc, char *argv[]) {	state_t curstate;	curstate.execute = stateA;	for(;;) {		curstate = curstate.execute();	}   getchar();   return 0;}state_t stateA() {	char c;	state_t s;	printf("State A\n");	for(;;) {		c = getch();		switch(c) {			case 'b': s.execute = stateB; break;			case 'c': s.execute = stateC; break;		}		return s;	}}state_t stateB() {	char c;	state_t s;	printf("State B\n");	for(;;) {		c = getch();		switch(c) {			case 'a': s.execute = stateA; break;			case 'c': s.execute = stateC; break;		}		return s;	}}state_t stateC() {	char c;	state_t s;	printf("State C\n");	for(;;) {		c = getch();		switch(c) {			case 'a': s.execute = stateA; break;			case 'b': s.execute = stateB; break;		}		return s;	}}

##### Share on other sites
timmay314    138
Quote:
 Original post by eightyI suppose you could return void* and cast the result back to a function when you want to use it, but a neater solution would probably be to use functors inheriting from an abstract base class State.

I had always assumed that "functor" was short for function pointer, but apparently that is not the case. So what exactly is a functor then?

##### Share on other sites
Stoffel    250
A functor is a class whose function operator (operator ()) has been overridden.

Example:
class Printer{public:   void operator () (const char *s)   {     cout << "I can print, says " << s << endl;   }};Printer p;p ("Stoffel"); // prints "I can print, says Stoffel"

Not a very exciting functor, but one nonetheless. Note the second void (the one in the argument list) is unnecessary, but that's where you'd put arguments. The return type can also be anything you want. You can treat the class objects like functions.

##### Share on other sites
eighty    220
snk_kid: The problem was he wanted to return a pointer of the same type as the function called was, ie be able to do this:
T function() { return function; }

T is not void, for that's not the type of the pointer. T is not void (*)(), for the return type of the returnee is not void. And so on, and so forth.

sbayeta: Nice solution. That's about how I would've done it.

##### Share on other sites
Guest Anonymous Poster
I do something in Python right now that I based on some work I did previously in C++. I lost the C++ version, so hopefully someone can figure out where I was coming from. I'll post the Python version, which is a little evolved from what I started with in C++, which I remember using exceptions to signal state changes. Anyway, what I do in Python is...

I created a class, as such:

class StateStack:    def __init__(self):        self._state_stack = []    def _push_state(self, _class):        self._state_stack.append(self.__class__)        self.__class__ = _class    def _pop_state(self):        self.__class__ = self._state_stack.pop()

My states are then sub-classes of this. When it needs to change state, it pushes that state onto the State Stack (pushes the class) and the object becomes that class, until the state is pushed.

Methods to switch completely (pop then push) the state would be easily implemented.

[Edited by - Fruny on August 5, 2004 4:09:31 AM]

##### Share on other sites
snk_kid    1312
Quote:
 Original post by eightysnk_kid: The problem was he wanted to return a pointer of the same type as the function called was, ie be able to do this:T function() { return function; }T is not void, for that's not the type of the pointer. T is not void (*)(), for the return type of the returnee is not void. And so on, and so forth.

Well if you read more closely i wasn't giving the solution i was giving an example of using function pointers.

##### Share on other sites
eighty    220
Quote:
Original post by snk_kid
Quote:
 Original post by eightysnk_kid: The problem was he wanted to return a pointer of the same type as the function called was, ie be able to do this:T function() { return function; }T is not void, for that's not the type of the pointer. T is not void (*)(), for the return type of the returnee is not void. And so on, and so forth.

Well if you read more closely i wasn't giving the solution i was giving an example of using function pointers.
I'm sorry. I got the impression he knew what function pointers were, he just didn't know how to solve this particular problem.