Sign in to follow this  
sbayeta

Function pointer question

Recommended Posts

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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
Quote:
Original post by eighty
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.


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 this post


Link to post
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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
Quote:
Original post by eighty
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.


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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Original post by eighty
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.


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

Share this post


Link to post
Share on other sites
Quote:
Original post by snk_kid
Quote:
Original post by eighty
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.


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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this