Function as parameter

Hello,

I want to write a function in which a function is passed. And the passed function will be called there.

I tried this:

unsigned long lastUpdate;
unsigned long updatePeriod = 1000;

void setup()
{}

void loop()
{
  virtualTimer(lastUpdate, updatePeriod, Test);
}

void virtualTimer(unsigned long &lastU, unsigned long updateP, void (*function) () )
{
  if (lastU + updateP > millis())
    {
      function();
      lastU = millis();
    }
}

void Test()
{
  Serial.println("It work :)");
}

Error:

Test.ino: In function 'void loop()': Test: error: 'virtualTimer' was not declared in this scope

Does anyone have a solution for me?

Thank you

The Arduino IDE first scans your sketch for any functions, and creates prototypes for them at the top of the compilation .cpp file.

This allows you to be lazy and define your functions in any order, even calling them higher up in your sketch that they are defined.

However, the IDE seems to fail with functions that have function pointers as parameters.

Define your virtualTimer function before you use it, or create a prototype for it at the top of your sketch, and all is well.

Add a function prototype:
void virtualTimer(unsigned long, unsigned long, void(*)());

And get rid of the &lastU and change it to lastU in the actual function definition.

EDIT: Are you sure this is right:
if (lastU + updateP > millis())

You might want to do something more like this instead:
if (millis() - lastU >= updateP)…

thx, it works great :D

afremont: Add a function prototype: void virtualTimer(unsigned long, unsigned long, void(*)());

And get rid of the &lastU and change it to lastU in the actual function definition.

EDIT: Are you sure this is right: if (lastU + updateP > millis())

You might want to do something more like this instead: if (millis() - lastU >= updateP)....

That is the accepted right way of doing it, yes.

As for the &lastU / lastU thing - it looks like lastU is being used as a reference to a variable outside the function to allow it to be used as a unique storage area for that specific virtual timer instance - as such either a byRef or a pointer will be required - dropping the byRef will stop it remembering when it was last called. Personally, as a C programmer and not commonly a C++ programmer, I'd use a pointer, not a byRef.

majenko:

afremont: Add a function prototype: void virtualTimer(unsigned long, unsigned long, void(*)());

And get rid of the &lastU and change it to lastU in the actual function definition.

EDIT: Are you sure this is right: if (lastU + updateP > millis())

You might want to do something more like this instead: if (millis() - lastU >= updateP)....

That is the accepted right way of doing it, yes.

Er, umm no. Aside from any rollover problems, his comparison is reversed

As for the &lastU / lastU thing - it looks like lastU is being used as a reference to a variable outside the function to allow it to be used as a unique storage area for that specific virtual timer instance - as such either a byRef or a pointer will be required - dropping the byRef will stop it remembering when it was last called. Personally, as a C programmer and not commonly a C++ programmer, I'd use a pointer, not a byRef.

Well, in that case, his call should look like this: virtualTimer(&lastUpdate, updatePeriod, Test); The function prototype should look like this: void virtualTimer(unsigned long , unsigned long, void()()); The function definition should look like this: void virtualTimer(unsigned long *lastU, unsigned long updateP, void (*function) () )

Personally, I would have just had the function return the new value of lastUpdate.

majenko: The Arduino IDE first scans your sketch for any functions, and creates prototypes for them at the top of the compilation .cpp file.

I wondered why it was so forgiving of forward references to non-prototyped functions. Thanks for mentioning that.

afremont:

majenko:

afremont:
You might want to do something more like this instead:
if (millis() - lastU >= updateP)…

That is the accepted right way of doing it, yes.

Er, umm no. Aside from any rollover problems, his comparison is reversed

Er, umm yes. I mean the way you show is the accepted right way of doing it, not his arse-about-face way :stuck_out_tongue:

As for the &lastU / lastU thing - it looks like lastU is being used as a reference to a variable outside the function to allow it to be used as a unique storage area for that specific virtual timer instance - as such either a byRef or a pointer will be required - dropping the byRef will stop it remembering when it was last called. Personally, as a C programmer and not commonly a C++ programmer, I’d use a pointer, not a byRef.

Well, in that case, his call should look like this:
virtualTimer(&lastUpdate, updatePeriod, Test);
The function prototype should look like this:
void virtualTimer(unsigned long , unsigned long, void()());
The function definition should look like this:
void virtualTimer(unsigned long *lastU, unsigned long updateP, void (*function) () )

Personally, I would have just had the function return the new value of lastUpdate.

Makes calling more complex returning an updated value - just pass a pointer is easiest (and lightest, as you don’t use any extra local variables). Passing by reference (unsigned long &variable) is the same as passing by pointer (unsigned long *variable) but you don’t end up with a pointer in your function, but a real variable (no *variable = 3, just variable = 3) which is simpler to program, but lazier in my opinion. But that’s C++ for you … compared to pure C, it breeds laziness… Especially in the hands of inexperienced Arduino programmers. Not as bad as Java, I grant you, and thank all that is holy that the Arduino isn’t programmed in Java, but still it does allow you to develop bad habits and not even know it…

majenko:

afremont:

majenko:

afremont: Add a function prototype: void virtualTimer(unsigned long, unsigned long, void(*)());

And get rid of the &lastU and change it to lastU in the actual function definition.

EDIT: Are you sure this is right: if (lastU + updateP > millis())

You might want to do something more like this instead: if (millis() - lastU >= updateP)....

That is the accepted right way of doing it, yes.

Er, umm no. Aside from any rollover problems, his comparison is reversed

Er, umm yes. I mean the way you show is the accepted right way of doing it, not his arse-about-face way :P

As for the &lastU / lastU thing - it looks like lastU is being used as a reference to a variable outside the function to allow it to be used as a unique storage area for that specific virtual timer instance - as such either a byRef or a pointer will be required - dropping the byRef will stop it remembering when it was last called. Personally, as a C programmer and not commonly a C++ programmer, I'd use a pointer, not a byRef.

Well, in that case, his call should look like this: virtualTimer(&lastUpdate, updatePeriod, Test); The function prototype should look like this: void virtualTimer(unsigned long , unsigned long, void()()); The function definition should look like this: void virtualTimer(unsigned long *lastU, unsigned long updateP, void (*function) () )

Personally, I would have just had the function return the new value of lastUpdate.

Makes calling more complex returning an updated value - just pass a pointer is easiest (and lightest, as you don't use any extra local variables). Passing by reference (unsigned long &variable) is the same as passing by pointer (unsigned long *variable) but you don't end up with a pointer in your function, but a real variable (no *variable = 3, just variable = 3) which is simpler to program, but lazier in my opinion. But that's C++ for you ... compared to pure C, it breeds laziness... Especially in the hands of inexperienced Arduino programmers. Not as bad as Java, I grant you, and thank all that is holy that the Arduino isn't programmed in Java, but still it does allow you to develop bad habits and not even know it...

To me it's cleaner and more clear to just say: lastUpdate = virtualTimer(lastUpdate, updatePeriod, Test); This way, no other function is stomping around on this functions data. I can't speak for C++, but & and * are not simply interchangeable, they are complimentary. A call would usually use the &name and the function def would have *name, never the &.

C++ adds the By Reference system, of defining a parameter to a function as &value, which passes by reference:

Pure C:

void increment(int *v)
{
  (*v)++;
}

int value = 4;
increment(&value);
// value == 5

C++ By Reference:

void increment(int &v)
{
  v++;
}

int value = 4;
increment(value);
// value == 5

Both have the same effect, but the C++ way hides the fact that you're calling the function with the parameter by reference - you just give it the variable and C++ knows to do it by reference by the function prototype, you don't have to specifically tell it with a pointer to the variable.

I think it makes it a whole lot harder to understand what is going on - it's not obvious if you're passing by value or by reference; with a pointer it's blindingly obvious.

The difference is most apparent when you're passing a struct or an object - passing by pointer you have to reference the object or struct with the -> pointer syntax, but passing it by reference you can continue to use the same . notation you use for the main instance of the class or struct.

struct foo {
  char bar;
};

struct foo fubar;

function ptr(struct foo *fu)
{
  fu->bar = 3;
}

function byref(struct foo &fu)
{
  fu.bar = 3;
}

// ...
ptr(&fubar);
byref(fubar);

The main difference is that a byRef variable cannot be re-assigned once assigned, whereas a pointer can. You can't have, say, an object instance as a byref and selectively asisgn it to any one of a number of actual object instances like you can with a pointer. It can only be assigned as part of a function call.

Personally I never use byRef if it can at all be avoided. I am a big fan of pointers. Took me years to get my head around them, but once they clicked I never looked back. I use them on a daily basis. I think I have actually used byRef parameters three times in my life, and only because someone else insisted that I do.

If I understand you, the called function gets to decide arbitrarily to be able to reach into the scope of the calling function. By just including the & in the function definition, the called function can just reach into the caller and modify the passed variable. Is that right?

afremont: If I understand you, the called function gets to decide arbitrarily to be able to reach into the scope of the calling function. By just including the & in the function definition, the called function can just reach into the caller and modify the passed variable. Is that right?

Yep.

It performs the same functionality as passing a pointer, but it hides the pointer from the programmer.