Calling functions with an integer?

First time poster, please forgive. I’ve been researching c++ resourses for a few hours now, and have had little luck. What I want to do is use 8 input pins to read in a parallel signal and get an integer value from it. With that integer I’d like to use it to call a function (sort of like functions at an address?). Storing functions at integers does not seem possible, and I don’t know if what I am trying to do is even possible. It sounds like it would utilize function pointers in some way, but I must admit I’m not sure how to go about that. Here’s what I’ve got so far.

void setup() {
  for(int j = 0; j <= 7; j++){
    pinMode(j,INPUT);
  };

}

void loop(){
int getKeycode(){
  for(int j = 0; j <= 7; j++){
    if(digitalRead(j) == HIGH){
      bitSet(code, j);
    }
    else{
      bitClear(code, j);
    };
  };
}
  return code;
}

With the returned integer “code,” I’d like to be able to call a function that corresponds to the code (There will be many inputs, and therefore functions possible).

Any advice, points in the right direction, or alternatives would be appreciated. Cheers.

What you want to do is fine, you just have the structure wrong, any function must be outside loop() which is itself a function.

void setup() {
  for(int j = 0; j <= 7; j++){
    pinMode(j,INPUT);
  }
}

Void loop(){
  int keyCode = getKeycode();
  // do something with keyCode
  NewFunction(keyCode);
}

int getKeycode(){
    int keyCode;

    for(int j = 0; j <= 7; j++){
      keyCode = keyCode | ( digitalRead(j) << j );
      }
  return code;
}

void newFunction(int keyCode){
  // code here
}

Code untested, it should work but it’s the concept I’m trying to show.

PS: karma given for posting code correctly in your first post.

PSS: while your looping code to initialize and read 8 consecutive inputs is fine, you don’t want to use inputs 0 and 1 in most Arduinos as these two pins are dedicated to the serial port that communicates with your computer via USB. While they can be used, it precludes being able to use the serial print commands for debugging and program output.

Thanks for the reply. I think I worded my post a bit ambiguously. My program will give the correct keyCode based on the input pins. Where I'm stumped is what to do with the code. If I've got 50 functions I want to be able to call, would I need to have 50 IF statements, one for each code, or for a lack of better terms, is there someway to say "here's an integer 'code', execute the function corresponding to it."

Thanks

Do you mean that you have 256 different functions, and you want to call a specific function based on the value returned by your getKeycode function?

You could use the switch statement, since the value is an integer:

https://www.arduino.cc/reference/en/language/structure/control-structure/switchcase/

I'm not terribly familiar with c++, but it does appear to support an array of function pointers, which would do what you want. This page has an example near the bottom that appears to do what you want:

http://www.gammon.com.au/callbacks

Perhaps it's time to explain what you're actually trying to do because this is starting to sound like an x-y problem

There are several ways to do what you're describing, each with their own pros and cons. It would help to know what you're ultimately doing and which Arduino you're thinking of running this on.

Come to think of it, my example is wrong because we should be using the "byte" type rather than a integer to hold the result of the 8 bit read. Using a byte would require a 512 byte function lookup table, using an int, 32768 bytes, the entire flash memory space of the Arduino Uno.

Details matter.

jswim83:
Thanks for the reply. I think I worded my post a bit ambiguously. My program will give the correct keyCode based on the input pins. Where I'm stumped is what to do with the code. If I've got 50 functions I want to be able to call, would I need to have 50 IF statements, one for each code, or for a lack of better terms, is there someway to say "here's an integer 'code', execute the function corresponding to it."

Thanks

I seriously doubt that you need 50 different functions. But, be that as it may, the structure you may be seeking is an array of function pointers. You'd use the integer to index into the array to select the corresponding pointer.

I think function pointers is the easiest and most efficient way to do this.

Since you’re reading eight bits you could store the result in a byte. The demo I wrote below uses an int but it doesn’t matter.

It defines a type called myFunc that is a pointer to a function that returns void and which accepts no parameters. While you can easily change this to whatever you want (returns int, bool, float etc, accepts anything…), the downside is that all functions referenced by this type must return the same type and accept the same type. In my example they’re void/void.

I then created an array of type myFunc and put as elements the addresses of each of three functions I created.

Loop calls a sample function that returns an int (in your case, it would be the byte value read back from the pins) and then calls the function pointed to by the array member at that index.

Although I don’t show it you need to be careful with this method to ensure the index into that array is valid. If it’s not, you’ll crash the processor (not permanently but your code won’t do what you think it should) because the data pulled out of a memory location not associated with the array is most likely not a pointer to a nice function :slight_smile:

#define NUM_FUNCS       3   //or as big as you have memory for

//important to put prototypes of the functions before the array below
//or the compiler may complain
void Function_1( void );
void Function_2( void );
void Function_3( void );
//... as many as you need

//create a type that is a pointer to a function that returns void and accepts no parms
//easy to change as required
//all functions of a same type must return the same type and accept the same parms
typedef void (*myFunc)();

//create an array of those pointers
myFunc Functions[] =
{
    &Function_1,
    &Function_2,
    &Function_3
};

void setup( void )
{
    //print something from each function to the SM
    Serial.begin( 9600 );
    
}//setup

void loop( void )
{
    int
        index;

    //get the integer from the "pin-reading" function
    index = ReturnIntFunction();
    
    if( index < NUM_FUNCS )         //make sure we stay within the table
        Functions[index]();         
    
    //pregnant pause for effect
    delay(1000);
   
}//loop

//some function that returns an int for demo
//here we just count up
int ReturnIntFunction( void  )
{
    static int
        cnt = -1;
        
    cnt++;
    if( cnt == NUM_FUNCS )
        cnt = 0;
        
    return( cnt );
}

//three functions that do something slightly different to see they're each being called.
void Function_1( void )
{
    Serial.println( "Function 1 here..." );
    
}//Function_1

void Function_2( void )
{
    Serial.println( "Function 2 here..." );
    
}//Function_2

void Function_3( void )
{
    Serial.println( "Function 3 here..." );
    
}//Function_3

gfvalvo:
I seriously doubt that you need 50 different functions. But, be that as it may, the structure you may be seeking is an array of function pointers. You'd use the integer to index into the array to select the corresponding pointer.

The OP ‘s 50 functions are most likely not numbered 0 to 49 so an array of pointers is not a one step solution. The first step would be a lookup table to translate the function code to the pointer index before indirectly calling the desired routine.

Blackfin:
...
//important to put prototypes of the functions before the array below
//or the compiler may complain
...

Prototype? What’s a prototype?

Arduino code don’t need no stinking prototypes...

Just one one the many hidden features... just like type checking. Don’t need no stinking type checking either. You’re free to write Fortran style code and still have it compile.

If your input number is only 50 or less, you could get by with 6 pins (bits), 6 bits can hold a number from 0 to 63. What are you using to set or clear the pins? Give an example of a function you would call with (for example), 4.

Don't need no stinking type checking either. You're free to write Fortran style code and still have it compile.

I don't understand what you mean. Can you please provide a small example ?

Hello WattsThat

WattsThat:
Arduino code don’t need no stinking prototypes...

If you don't use prototypes, you have to put the whole functions code before the declaration of the array of pointers.
Not very readable.

Regards,
bidouilleelec

With the prototypes not declared the IDE gives the following errors:

Arduino: 1.8.8 (Windows 10), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

sketch_feb16d:19:6: error: 'Function_1' was not declared in this scope

     &Function_1,

      ^

sketch_feb16d:20:6: error: 'Function_2' was not declared in this scope

     &Function_2,

      ^

sketch_feb16d:21:6: error: 'Function_3' was not declared in this scope

     &Function_3

      ^

exit status 1
'Function_1' was not declared in this scope

As bidouilleelec suggests, a potential workaround is to have the functions before the declaration of the array. Could work but wouldn't be ugly.

Blackfin, thank you for your advice and helpful example! Much appreciated

UKHeliBob:
I don't understand what you mean. Can you please provide a small example ?

Sure, that's easy to do. The buggie code below compiles without errors or warnings.

Arduino provides simplicity by throwing the hard learned rules of C and C++ out the window. This freedom from the rules comes at the cost of undetected errors. Actually, they're intentionally ignored.

This is not a complaint, just my observation of how the lack of rules can create incredibly bad programming habits that (IMO) can prevent many (most?) Arduino users from developing decent programming skills because they're never forced to understand the core, underlying language and just as importantly, the hardware. But hey, to keep things in perspective, you cannot ignore the success of the platform.

With respect to eliminating the rules, the quote the line from the Spiderman movie comes to mind: "With great power comes great responsibility".

IMO, you'll only find experienced C and C++ programmers being reasonably productive with the Arduino environment because they already understand the rules. If you don't believe me, I challenge you to find the phrases "prototype" or "type checking" in the Arduino language documentation. Please let me know if you find them anywhere outside of the forum, I've never seen those topics mentioned.

Oh, yeah, I know, I don't define reasonably productive. That's my just my belief. Don't feel the need to try and sway/move/change my opinion. I'm an old fart.

PS: Compiled in 1.8.3 Mac and tested on clone Uno.

void setup() {
  int varInt;
  byte varByte;

  Serial.begin(115200);
  Serial.println("");
  
  varInt = 0x2710;
  // prints 0x2710, CORRECT
  Serial.println(varInt,HEX);
  varByte = 0x64;
  Serial.println(varByte,HEX);
  // prints 0x64, CORRECT

  // fails queitly, C and C++ type checking would flag this
  varByte = varInt;
  // prints 0x10, INCORRECT okay for LSB but not expected value
  Serial.println(varByte,HEX);

  // fails queitly, C and C++ type checking would flag this
  varInt = varByte;
  // prints 0x10, CORRECT
  Serial.println(varInt,HEX);

  // no prototype required for forward reference, no warning or error
  // C would return warning for incorrect calling type
  // fails queitly for all issues
  // function call prints 0x10 which is the LSB of 0x2710
  // okay but not what the user expects
  varInt = functionRetunsInt(varInt);
  // prints 0x10, INCORRECT, 0x2AF8 expected
  Serial.println(varByte,HEX);

  // change the return type and this also fails quietly in a different way
  // function call prints 0xE8 which is the LSB of 0x03E8
  // which is coming directly from the routine without any addition being performed
  // so the function behaves differently depending upon the assigned return type
  varByte = functionRetunsInt(varInt);
  // prints 0xE8, INCORRECT, 0x2AF8 expected
  Serial.println(varByte,HEX);

}

void loop() {}

int functionRetunsInt(byte value) {

  byte retVal;
  int varInt = 0x3E8; // 1000 decimal

  Serial.print("passed value = ");
  Serial.println(value,HEX);

  retVal += varInt;
  return retVal;
}