How to Structure Array of Function Pointers

Most Google searches result in "array of function pointers in c", and very little for Arduino. Either these examples/explanations don't work on Arduino, the newer IDE can't handle array or function pointers, or I don't really understand array of function pointers. I have found this link from here:

http://forum.arduino.cc/index.php/topic,40842.0.html

This thread is ~5 years old and it doesn't seem to work with Arduino 1.0.3, or Arduino 1.0.5.

Does anyone know know how to structure array of function pointers for Arduino?

My application is a generic menu library, which would respond to GPIO input and display the button-navigated menu on a LCD/LCD-I2C.

So far, this is what I have, since I've just started a couple days ago and I'm stuck at the array of function pointers:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Bounce.h>

#define Button_1  9
#define LED_1 13

LiquidCrystal_I2C lcd(0x3F, 20, 4);
Bounce button_1 = Bounce(Button_1, 5);

void (*Page_1)(int foo);

typedef void (* GenericFP)();
GenericFP MenuFP[2] = {Page2, Page3};

int button_1_toggle = LOW;

void setup()
{
  pinMode(Button_1, INPUT);
  pinMode(LED_1, OUTPUT);
  
  lcd.init();
  lcd.backlight();

  Page_1 = &Page1;
}

void loop()
{
  toggle(&button_1, &button_1_toggle);
  Page1(1);
  
  switch(button_1_toggle)
  {
    case HIGH:
      lcd.backlight();
      break;
    case LOW:
      lcd.noBacklight();
      break;
  }
  lcd.setCursor(0,0);
}

void toggle(Bounce* Button, int *ToggleValue)
{
  if (Button->update())
  {
    if (Button->read() == HIGH)
    {
      if (*ToggleValue == LOW)
      {
        *ToggleValue = HIGH;
      }
      else
      {
        *ToggleValue = LOW;
      }
    }
  }
}

void Page1(int foo)
{
};

void Page2(int foo)
{
};

void Page3(int foo)
{
};

Excuse the jumble. toggle() is a working function that takes input from a switch on pin D9 and toggles an LED on pin D13 and the LCD backlight.

The part that is not working is the array portion starting with the typedef. The typedef is based on the link above. The IDE is failing on:
GenericFP MenuFP[2] = {Page2, Page3};

The error message that is presented is "expected primary-expression before 'int'

These two lines are basically what is presented in the link but does not work with the newer IDE.

Any assistance is appreciated.
Thanks in advance.

typedef wrong. Must be:
typedef void (* GenericFP)(int);
It's not so generic, it is a pointer to a function with one int parameter and no return

If you declare a typedef, use it also for the pointer. It's more readable:
void (*Page_1)(int foo); => GenericFP *Page_1=NULL;

typedef void (* GenericFP)(int);
GenericFP *Page_1=NULL;
GenericFP MenuFP[2] = {Page2, Page3};

P.S. Please @daduck use special tag for the code (button with #)

http://forum.arduino.cc/index.php?topic=170230.msg1266379#msg1266379

Here is an example of function pointers:

typedef void (* GenericFP)(int); //function pointer prototype to a function which takes an 'int' an returns 'void'

GenericFP MenuFP[3] = {&Page1, &Page2, &Page3}; //create an array of 'GenericFP' function pointers. Notice the '&' operator

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  MenuFP[0](1); //call MenuFP element 0 with the parameter 1.  This is equivalent to: Page1(1)
  MenuFP[1](5); //call MenuFP element 1 with the parameter 5.  This is equivalent to: Page2(5)
  MenuFP[2](7); //and so on.                                   This is equivalent to: Page3(7)
}

void Page1(int foo)
{
  Serial.print("Page1=");
  Serial.println(foo);
}

void Page2(int foo)
{
  Serial.print("Page2=");
  Serial.println(foo);
}

void Page3(int foo)
{
  Serial.print("Page3=");
  Serial.println(foo);
}

C allows for some pretty complex data definitions. The Right-Left Rule can help figure out what you have really defined:

http://jdurrett.ba.ttu.edu/3345/handouts/RL-rule.html

Would I be able to use the array of function pointers to functions of varying number of arguments by way of
typedef void (* GenericFP)(int) or would this definition need to be modified in some way?

Thanks everyone. I'll have to try your examples and post my results.

daduck748:
Would I be able to use the array of function pointers to functions of varying number of arguments by way of
typedef void (* GenericFP)(int) or would this definition need to be modified in some way?

Thanks everyone. I'll have to try your examples and post my results.

Sorry it's not possible. Every array element must be of same type.
For a function the number of parameters is the signature of the function and is very important for compiler.

nid69ita: What about the ellipsis operator? Also, you could have an array of pointers to functions where the argument is a structure, and then "fill in" only those structure elements that are needed for a particular function, setting the unused members to null or zero might work. Ugly, but it might meet his needs.

Wouldn't that be the same thing as a function pointer with say, 15 arguments, and each function "picking and choosing" the arguments necessary?

However, passing a data structure is much more elegant.

I did come across a forum that talked about an array of function pointers with different arguments. I wish I had saved it. However, it seems things that work in c don't necessarily work under the Arduino platform.

econjack:
nid69ita: What about the ellipsis operator? Also, you could have an array of pointers to functions where the argument is a structure, and then "fill in" only those structure elements that are needed for a particular function, setting the unused members to null or zero might work. Ugly, but it might meet his needs.

Not easy using a structure.
I don't undestand Ellipsis operator. They are for variant argument?

If you mean variadic functions, you can do that, for example:

typedef void (* GenericFP)(void*, ...); //function pointer prototype to a function which takes an 'int' an returns 'void'

void Page1(void* skip, ...);
void Page2(void* skip, ...);
void Page3(void* skip, ...);
GenericFP MenuFP[3] = {&Page1, &Page2, &Page3}; //create an array of 'GenericFP' function pointers. Notice the '&' operator

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  MenuFP[0](NULL,1);
  MenuFP[1](NULL,5,3.444);
  MenuFP[2](NULL,7,2.77,"Hello");
}

void Page1(void* skip, ...)
{
  va_list args;
  va_start(args, skip);
  int foo1 = va_arg(args, int);
  
  Serial.println("Page1=");
  Serial.println(foo1);
}

void Page2(void* skip, ...)
{
  va_list args;
  va_start(args, skip);
  int foo1 = va_arg(args, int);
  float foo2 = (float)va_arg(args, double);
  
  Serial.println("Page2=");
  Serial.println(foo1);
  Serial.println(foo2);
}

void Page3(void* skip, ...)
{
  va_list args;
  va_start(args, skip);
  int foo1 = va_arg(args, int);
  float foo2 = (float)va_arg(args, double);
  const char* foo3 = va_arg(args, const char*);
  
  
  
  Serial.println("Page3=");
  Serial.println(foo1);
  Serial.println(foo2);
  Serial.println(foo3);
}

Note that all functions have to be of the same prototype, hence the void* followed by the variable arguments list. You can just ignore the void* in all of your functions, you just have to make sure that you pass a NULL as the argument - its just there to start the arguments list.

daduck748:
Does anyone know know how to structure array of function pointers for Arduino?

This compiles and runs as expected:

typedef void (* GenericFP)(int);

GenericFP MenuFP[] = {Page1, Page2, Page3};

int i = 0;

void setup()
  {
  Serial.begin (115200);
  }

void loop()
  {
  
  MenuFP [i++] (42);
  
  if (i >= 3)
    i = 0;
    
  delay (1000);
  }

void Page1(int foo)
  {
  Serial.println ("page1");
  }

void Page2(int foo)
  {
  Serial.println ("page2");
  }

void Page3(int foo)
  {
  Serial.println ("page3");
  }

However, it seems things that work in c don't necessarily work under the Arduino platform.

The arduino is programmed in C/C++ using the gcc compiler, so you should expect any C constructs to work as they do elsewhere. It is true that some library functionality is missing to save space - e.g. sprintf can't handle float arguments, but there's no "arduino platform" per se, it's all regular C/C++ under the covers.

Nick: You could also do away with the typedef:

void  (*MenuFP[])(int) = {Page1, Page2, Page3};

int i = 0;

void setup()
  {
  Serial.begin (9600);
  }

void loop()
  {
  
  MenuFP [i++] (42);
  
  if (i >= 3)
    i = 0;
    
  delay (1000);
  }

void Page1(int foo)
  {
  Serial.println ("page1");
  }

void Page2(int foo)
  {
  Serial.println ("page2");
  }

void Page3(int foo)
  {
  Serial.println ("page3");
  }

In the first line, you can use the Right-Left rule I mention above to see that MenuFP is: An array of pointers to functions with an int parameter returning void.

econjack:
Nick: You could also do away with the typedef:

Good point. I was just used to making one because I usually put a function pointer inside a struct (hmmm - maybe that doesn't totally explain it) but I'm sure there is usually a reason for it. :slight_smile:

I'm sorry to bump this thread, but I used your example successfully.
I'm a bit puzzled about the (42) though. It seem to run with any int I fill in.
What does it mean? Milliseconds reserved for each function?

The function takes an int argument. the (42) is that argument.

Still not clear to me.
Why doesn't anything change when I fill in another number?
I mean, if it's an argument, it should do something no?

Sorry for the noob question.

42 is the answer that "deep thought", the computer in the Hitchhiker's Guide to the Galaxy produced. You can give it any number because given that number, it will take a million times as long for the Arduino to figure out what the question was.

When creating a function that returns or accepts (or both) a function pointer, or even then an array of them things can become a mess. Typedefs are always handy (except I hate them being used to define structs that do not provide any additional substance, C-isms).

Imagine trying to explain this function to someone:

void (*(&doStuff(void (*(&in)[5])(int)))[5])(int){
  return in;
}

Whereas typedefs make this nice.