Finite State Machine Matrix-Style-C-Implementation (Function Pointers Addon)
I posted my solution for Finite State Machines in C using Matrix. Jean-Marc (f1hdi.org) commented to that entry:
I would love to have the state event matrix not only returning a ‘next state’ and action to do BUT directly calling ‘actions’ functions. A long time ago , when I was at school, I wrote such ptr function call but can’t reproduce it now.
Basically , in your routine below, I would love to replace the ‘return’ by a call to a function which you would have its pointer in the matrix.
Any idea ?
The simple answer to Jean-Marc’s questions is “Yes” and I’m really sorry that I hadn’t got the time to answer sooner. The basic idea of using function pointers is the right choice to find a solution for this task.
So what are functions pointers basically?
First of all a pointer is a data type whose value is “pointing” to a specific address in memory. “Dereferencing” a pointer returns the value stored at that specific address. Defining a pointer is done with an asterisk before the identifier of the variable. A pointer is assigned via the “adress of”-operator & and dereferencing a pointer is done with an asterisk before the identifiers name again.
int *a;
int b=5;
a = &b; // a is given the adress of b, a = 5
b = *a + 10; // b = 15
&b = a; // b is given the adress of a, b = 5
Function pointers point to the adress of a c-function. Dereferencing a function pointer means to envoke the apropriate function. The syntax for letting a variable point to a function differs from the above example. Pointing to a function is done via
void main() {
void (*fp)();
fp functionPointer = function_a;
(*fp)(); //prints "a"
fp functionPointer = function_b;
(*fp)(); //prints "b"
}
void function_a(void) {
fprintf("a \n");
}
void function_b(void) {
fprintf("b\n");
}
What to do with function pointers?
So these are function pointers, but why do whe need them?
// from: http://www.newty.de/ftp/intro.html#why
float Plus (float a, float b) { return a+b; }
float Minus (float a, float b) { return a-b; }
float Multiply(float a, float b) { return a*b; }
float Divide (float a, float b) { return a/b; }
// Solution with a switch-statement - specifies which operation to execute
void Switch(float a, float b, char opCode)
{
float result;
// execute operation
switch(opCode)
{
case '+' : result = Plus (a, b); break;
case '-' : result = Minus (a, b); break;
case '*' : result = Multiply (a, b); break;
case '/' : result = Divide (a, b); break;
}
cout << \"Switch: 2+5=\" << result << endl; // display result
}
// Solution with a function pointer
// a function which takes two floats and returns a float. The function pointer
// "specifies" which operation shall be executed.
void Switch_With_Function_Pointer(float a, float b, float (*pt2Func)(float, float))
{
float result = pt2Func(a, b); // call using function pointer
}
// Execute example code
void Replace_A_Switch()
{
Switch(2, 5, /* '+' specifies function 'Plus' to be executed */ '+');
Switch_With_Function_Pointer(2, 5, /* pointer to function 'Minus' */ &Minus);
}
Changing the Type Definitions from the Matrix-Style-Implementation
You should have a look at my old post on how to implement a Matrix-Style-Implementation of Finite State Machines in C, to understand how the general mechanisms on this implementation work. I won’t recapitulate theme here.
First off all, you’ll have to define the generic typedefs for the state-event matrix as mentioned in the older implementation:
/*****************************************************************
* typedefs
*****************************************************************/
typedef enum {
STATE1,
STATE2,
STATE3
} state;
typedef enum {
NILEVENT,
EVENT1,
EVENT2
} event;
These are exactly the same data types as the approach without function pointers. We’ll now define a typedef for a function pointer to an action that shall be released in each state, the action-functions and the generic state-machine function:
typedef void (*action)(); // General functions void stateEval(event e); void exit(int status); void getIOValues(void); //Actions void action1_1(void); void action1_2(void); void action1_3(void); void action2_1(void); void action2_2(void); void action2_3(void); void action3_1(void); void action3_2(void); void action3_3(void);
The action function-pointer and state enumerators are combined in a structure typedef used for the function-pointer based state-event matrix:
typedef struct {
state nextState; // Enumerator for the next state
action actionToDo; // function-pointer to the action that shall be released in current state
} stateElement; // structure for the elements in the state-event matrix
And finally the state-event matrix will be build-up:
stateElement stateMatrix[3][3] = {
{ {STATE1, action1_1}, {STATE2, action1_2}, {STATE3, action1_3} },
{ {STATE2, action2_1}, {STATE2, action2_2}, {STATE3, action2_3} },
{ {STATE3, action3_1}, {STATE3, action3_2}, {STATE3, action3_3} }
};
And this will be the state-machine invocation with function-pointers involved
All these snippets go into the Header-File.
#include
#include "main.h"
state currentState = STATE1;
int main()
{
//Initializations
event eventOccured = NILEVENT;
action actionToDo = action1_1;
while(1) {
// event input, NIL-event for non-changing input-alphabet of FSM
// in real implementation this should be triggered by event registers e.g.
// evaluation of complex binary expressions could be implemented to release the events
int e = 0;
printf("----------------\n");
printf("Event to occure: ");
scanf("%u",&e);
stateEval( (event) e); // typecast to event enumeration type
printf("-----------------\n");
};
return (0);
}
/********************************************************************************
* stateEval (event)
* in Dependancy of an triggered event, the action wich is required by this
* transition will be returned. The proper action is determined by the current state the
* automat holds. The current state will then be transitioned to the requestet next
* state
********************************************************************************/
void stateEval(event e)
{
//determine the State-Matrix-Element in dependany of current state and triggered event
stateElement stateEvaluation = stateMatrix[currentState][e];
//do the transition to the next state (set requestet next state to current state)...
currentState = stateEvaluation.nextState;
//... and fire the proper action
(*stateEvaluation.actionToDo)();
}
/**********************************************************************
* action functions
**********************************************************************/
void action1_1() {
printf("action1.1 \n");
}
void action1_2() {
printf("action1.2 \n");
}
void action1_3() {
printf("action1.3 \n");
}
void action2_1() {
printf("action2.1 \n");
}
void action2_2() {
printf("action2.2 \n");
}
void action2_3() {
printf("action2.3 \n");
}
void action3_1() {
printf("action3.1 \n");
}
void action3_2() {
printf("action3.2 \n");
}
void action3_3() {
printf("action3.3 \n");
}
Elcoj
Hello,
http://www.gedan.net to GoogleReader!
May 23, 2009 @ 9:49 pm
mcdonalds coupons
Thank you very much for that awesome post.
Sep 14, 2009 @ 3:40 pm