Author Topic: Question on function pointers and callbacks  (Read 2835 times)

0 Members and 1 Guest are viewing this topic.

Offline unscriptedTopic starter

  • Contributor
  • Posts: 19
  • Country: pr
Question on function pointers and callbacks
« on: February 20, 2023, 02:16:14 am »
Rather than callbacks itself, this may be more a C programming-related question.  Going through some callbacks examples I'm stuck in understanding this one:

In an object file I see these declarations:

Code: [Select]
//Prototype for the function in the application program
void callback_execution(void(*fn)(void));

//initialize fp pointer to point to callback_execution( ))
void (*fp)(void(*fn)(void)) = &callback_execution;

//Function to toggle some pins
void callback_function(void)
{
    //toggle some pins           
}

//Timer interrupt handler
void timer_handler()
{
//Check for timer interrupt and clear it. Then call the function pointed to by fp
// callback_execution( ) is pointed to by fp and
// resides in the main application program.   

        fp(&callback_function);
}


So let me see if I understand how this works:

Here I'm registering the callback_execution function.

Code: [Select]
void (*fp)(void(*fn)(void)) = &callback_execution;

Then in the interrupt handler fp is called that points to callback_execution AND it is passed the address of callback_function as parameter.

Code: [Select]
fp(&callback_function);

Here it's where I'm confused. fp was initialized to point to callback_execution. But I'm passing callback_function address as the argument of fp. Does this mean callback_execution will be called and passed callback_function as its argument? The function prototype void callback_execution(void(*fn)(void)); is only defined in the main application but I don't see it is being explicitly called. So I'm assuming is being implicitly called by fp. Correct me where I'm wrong.

 

Online cv007

  • Super Contributor
  • ***
  • Posts: 1068
Re: Question on function pointers and callbacks
« Reply #1 on: February 20, 2023, 02:51:16 am »
You can test in the online compiler-

https://godbolt.org/z/4cbcbcedr

The callback_execution function needs to be somewhere, as the declaration just informs the compiler it will be somewhere.

The fp is a function pointer that when used takes a function pointer as an argument. When fp is used via (), it will need an argument of the type it was declared with- void(*)(), which in this case is the callback_function function. The functions do not need & as that is implied for functions.

It seems like quite a route to take to get to your function (timer_handler to callback_execution via fp, to callback_function inside callback_execution), but they may have reasons to do this even if they are not good reasons (maybe the callback_execution is doing logging or other things in addition to calling your function). It can be quite confusing when they decide to create these layers.
 
The following users thanked this post: unscripted

Offline unscriptedTopic starter

  • Contributor
  • Posts: 19
  • Country: pr
Re: Question on function pointers and callbacks
« Reply #2 on: February 20, 2023, 03:10:19 am »
It seems like quite a route to take to get to your function (timer_handler to callback_execution via fp, to callback_function inside callback_execution), but they may have reasons to do this even if they are not good reasons (maybe the callback_execution is doing logging or other things in addition to calling your function). It can be quite confusing when they decide to create these layers.

Thank you. That route is what it's still confusing to me. I get your point. The confusion for me is because fp(&callback_function) doesn't show callback_execution explicitly. So I thought it would call callback_function directly. If I were to read the function I'd say that callback_execution is called by fp implicitly in the expression fp(&callback_function). And callback_execution is passed callback_function as the argument.
 

Offline slugrustle

  • Frequent Contributor
  • **
  • Posts: 329
  • Country: us
Re: Question on function pointers and callbacks
« Reply #3 on: February 20, 2023, 03:53:12 am »
That example is also really odd to me because I don't think there's a point to using callbacks unless you're passing around the pointer to the callback function dynamically at runtime.
 

Offline pcprogrammer

  • Super Contributor
  • ***
  • Posts: 6140
  • Country: nl
Re: Question on function pointers and callbacks
« Reply #4 on: February 20, 2023, 06:49:53 am »
Callbacks are often used in hardware abstraction layers and use static pointers or fixed function names to make it work, but the given example is indeed weird.

In this case the function has to be named "callback_execution" in the application part and has to have "void(*fn)(void)" as input parameter. They then use a global function pointer to call it in the interrupt handler.

The only advantage I see for it, is the ability for the application programmer to use the global function pointer "fp" to set a different callback function at run time.

The fact that it passes the execution address of the function allows some sort of verification as to which function is being used?

Yep definitely weird.

Online Berni

  • Super Contributor
  • ***
  • Posts: 5430
  • Country: si
Re: Question on function pointers and callbacks
« Reply #5 on: February 20, 2023, 07:10:04 am »
Yeah this does not make any sense for passing itself as a parameter.

Maybe the function would do something else if you pass it a different pointer, like making a chain of calls or something.

Normally callback functions would have a pointer to some sort of context structure instead. Like if you have 1 function servicing multiple timer interrupts you would pass in the timers address or perhaps some structure that has the timer address as part of it. Tho this is basically just implementing the functionality of C++ classes using regular C features.
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 6564
  • Country: gb
Re: Question on function pointers and callbacks
« Reply #6 on: February 20, 2023, 10:35:30 am »
This looks like a use of dynamic function pointer callbacks such as used in Closure or Javascript.  Everything is a function that takes a function and returns a function which takes a function.  Apparently some peoples brains actually work that way, but no, really it's easier to implement in ASM.

I have used function pointer arguments, for chaining call backs to create "do this", then "do this", unless this, then "do this" interrupt chains. 

I can see how assigning those function pointers (static pointers) in my case to a variable might be useful. 

These techniques also for a lot of the basis of C++ OOP under the hood and reoccurs a lot generally in OOP for everything from inheritance, to polymorphism.

del = object->getDeligate( candidate );
results = del->process( candidate );
ui->getRenderer( results )->render();

Would basically be a whole set of dynamic struct and dynamic function pointers in C.
"What could possibly go wrong?"
Current Open Projects:  68000 Self Build computer + OS.
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: Question on function pointers and callbacks
« Reply #7 on: February 20, 2023, 12:40:58 pm »
Yup, calling fp(&callback_function) is quite odd; one would expect it to be fp(), i.e. passing no parameters, because of the function pointer type.

There are three very commonly used patterns, if it matters:
  • Passing a function pointer to a function be applied for array members.  See qsort() standard C library function, which takes a pointer to a function used to compare array elements.
     
  • Passing the pointer of a structure where the function pointer itself resides, roughly similarly to OOP this or self keywords.
    An example is generic list/array/hash table support, where the structure is an instance of the data store, and contains function pointer(s) for specific operations.  By implementing the operation functions for different types of data elements, user can use the same interface for all datastores of that type, regardless of which of the supported element data types it uses.
     
  • Passing a private pointer to the function, stored in the same structure.
    An example is a driver structure, or an instance of for example human interface button handler in a microcontroller firmware, where the private pointer contains the instance-specific information.  The main structure can then support different types of elements, each type having their own handler functions, and taking a pointer to the instance-specific private information, which is opaque from outside.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

- - -
-->