It is right, that you are putting brackets after the function name if you are calling it. But with attachInterrupt()
you just want to give it the information, which function to call in case of an interrupt. With the brackets the compiler would think you want the function to be executed and the result/return value being given as parameter to attachInterrupt()
. But the execution here should only happen in case of an interrupt. The attachInterrupt()
function/the corresponding ISR need to know, what to call in case of an interrupt. Just the information/address of the function.
Maybe you have already heard of pointers. That are variables that hold the address of a different variable. They are pointing somewhere else in the memory. blink
(without the brackets) is basically a function pointer. Leaving the brackets away tells the compiler, that you want the address of the function, not executing it. You are providing the function parameter by reference this way, providing the address, not the value.
If you like/need you can use that principle yourself by defining your own function pointer variable. For example this
void (*myCallbackFunction)(int);
which is a function, that takes an int as parameter and returns nothing (void). You can then set the function pointer and call it as a normal function
void blinkXTimes(int times){
for(int i=0;i<times;i++){
digitalWrite(pin, HIGH);
delay(500);
digitalWrite(pin, LOW);
delay(500);
}
}
void setup(){
pinMode(pin, OUTPUT);
myCallbackFunction = blinkXTimes;
void loop(){
myCallbackFunction(3);
delay(5000);
}
We are calling myCallbackFunction()
, but it is a function pointer, that points to blinkXTimes()
, so that will be executed.
So, what's going on here, and are there other scenarios where you might use a function without the brackets after it?
The above principle is super useful for writing libraries with user callback functions. Another example (besides attachInterrupt()
) is the Wire
library. There the receive and request interrupts need to interact with the library user to deliver to or request data from him. For this the Wire
library lets you set your own callback functions. Refer to the examples of that library.
Another application would be building a Finite State Machine with a function pointer (basically calling different functions on each loop iteration depending on the state, which is represented by the function pointer).
That are the two big application I know of. The first one is more common. Though function pointers are just a tool. They can be used for many things.