Pointers to Functions and Callbacks in C

Function Pointers provide some extremely interesting, efficient and elegant programming techniques. You can use them to replace switch/if-statements, to implement callbacks. probably due to their complicated syntax – beginners find it hard to understand them. In fact, they are less error causing  than normal pointers cause you will never allocate or deallocate memory with them. All you’ve got to do is to understand what they are and to learn their syntax. But keep in mind: Always ask yourself if you really need a function pointer. they  may make your code more readable and clear.

What is a Function Pointer?

Function Pointers are pointers, i.e. variables, which point to the address of a function. You must keep in mind, that a running program gets a certain space in the main-memory.Both, the executable compiled program code and the used variables, are put inside this memory. Thus a function in the program code is, like  a character field, nothing else than an address. It is only important how  your compiler, interpret the memory a pointer points to.

 

 

 

How to define a Function Pointer

int (*pt2Func)(float ,float ) = NULL;

or you can define it as a type which would make it easy to use

typedef int (*pt2Func)(float ,float );

Assign an address to a Function Pointer

It’s quite easy to assign the address of a function to a function pointer. You simply take the name of a suitable and known function or member function. Although it’s optional for most compilers you should use the address operator & infront of the function’s name.

int function1(float a,float b)
{
 return a+b;
} int function2(float a,float b)
{
return a-b;
}
 pt2Func = function1; // short form
 pt2Func = &function2;

Important note: A function pointer always points to a function with a specific signature! Thus all functions, you want to use with the same function pointer, must have the same parameters and return-type!

Calling Convention

Normally you don’t have to think about a function’s calling convention: The compiler assumes __cdecl as default if you don’t specify another convention. However if you want to know more, keep on reading … The calling convention tells the compiler things like how to pass the arguments or how to generate the name of a function. Some examples for other calling conventions are __stdcall, __pascal and__fastcall. The calling convention belongs to a function’s signature: Thus functions and function pointers with different calling convention are incompatible with each other!  For the GNU GCC you use the __attribute__ keyword: Write the function definition followed by the keyword __attribute__ and then state the calling convention in double parentheses.

float function1(float a,float b) __attribute__((cdecl));

Calling a Function using a Function Pointer

In C  you call a function using a function pointer by explicitly dereferencing it using the
* operator. Also, you may  just use the function pointer’s instead of the function name.

float result1 = pt2Function (2,5); // C short way
float result2 = (*pt2Function) (2,5)); // C

consider the following demonstrative example. It’s <b>only an example</b> and the task is so easy that I suppose nobody will ever use a function pointer for it

/*
 * main.c
 *
 * Created: 7/2/2016 9:30:05 PM
 * Author: Kareem A.Abdullah
 */

#include &amp;amp;lt;stdio.h&amp;amp;gt;
#include &amp;amp;lt;stdlib.h&amp;amp;gt;
#include "operations.h"
int main()
{
 printf("result using switch case =%f\n",Switch(2, 5, '+'));
 printf("result using funcptr case =%f\n",Switch_With_FuncPtr(2, 5, &amp;amp;amp;Plus));
 return 0;
}
/*
 * operations.c
 *
 * Created: 7/2/2016 9:31:08 PM
 * Author: Kareem A.Abdullah
 */

float Plus (float a, float b)
{
 return a+b;
}
float Minus (float a, float b)
{
 return a-b;
 }
float Multiply(float a, float b)
{
 return a*b;
 }
float Divide (float a, float b)
 {
 return a/b;
}
// using a switch-statement - operation
// specifies which operation to execute
float Switch(float a, float b, char operation)
{
 float result;
 switch(operation)
 {
 case '+' : result = Plus (a, b); break;
 case '-' : result = Minus (a, b); break;
 case '*' : result = Multiply (a, b); break;
 case '/' : result = Divide (a, b); break;
 }
 return result;
}

// using a function pointer - pt2Fuc is a function pointer and points to
// a function which takes two floats and returns a float. The function pointer
// which operation shall be executed.
float Switch_With_FuncPtr(float a, float b, float (*pt2Func)(float, float))
{
 float result = pt2Func(a, b); // call using function pointer
 return result;

}
/*
 * operations.h
 *
 * Created: 7/2/2016 9:31:50 PM
 * Author: Kareem A.Abdullah
 */

#ifndef OPERATIONS_H_INCLUDED
#define OPERATIONS_H_INCLUDED

float Plus (float a, float b);
float Minus (float a, float b);
float Multiply(float a, float b);
float Divide (float a, float b);

float Switch(float a, float b, char operation);
float Switch_With_FuncPtr(float a, float b, float (*pt2Func)(float, float));

#endif // OPERATIONS_H_INCLUDED

the two calls return the same value as you can see

22222222

the Concept of Callback Functions

In computer programming, a callback is a reference to executable code, or a piece of executable code, that is passed as an argument to other code. This allows a lower-level software layer to call a function defined in a higher-level layer.

 How to Implement a Callback in C ?

Let’s try one simple program to demonstrate this. The complete program has three files:callback.creg_callback.h and reg_callback.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* callback.c */
#include<stdio.h>
#include"reg_callback.h"
/* callback function definition goes here */
void my_callback(void)
{
    printf("inside my_callback\n");
}
int main(void)
{
    /* initialize function pointer to
    my_callback */
    callback ptr_my_callback=my_callback;                           
    printf("This is a program demonstrating function callback\n");
    /* register our callback function */
    register_callback(ptr_my_callback);                             
    printf("back inside main program\n");
    return 0;
}
1
2
3
/* reg_callback.h */
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);
1
2
3
4
5
6
7
8
9
10
11
/* reg_callback.c */
#include<stdio.h>
#include"reg_callback.h"
/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
    printf("inside register_callback\n");
    /* calling our callback function my_callback */
    (*ptr_reg_callback)();                                  
}
Compile, link and run the program
145
The code needs a little explanation. Assume that we have to call a callback function that does some useful work (error handling, etc.), after an event occurs in another part of the program. The first step is to register the callback function, which is just passing a function pointer as an argument to some other function ( register_callback) where the callback function needs to be called.
We could have written the above code in a single file, but have put the definition of the callback function in a separate file to simulate real-life cases, where the callback function is in the top layer and the function that will invoke it is in a different file layer. So the program flow is follows

function-callback-1

The higher layer function calls a lower layer function as a normal call and the callback mechanism allows the lower layer function to call the higher layer function through a pointer to a callback function.
Callback functions can also be used to create a library that will be called from an upper-layer program, and in turn, the library will call user-defined code on the occurrence of some event. The following source code (insertion_main.cinsertion_sort.c and insertion_sort.h), shows this mechanism used to implement a trivial insertion sort library. The flexibility lets users call any comparison function they want.
1
2
3
4
/* insertion_sort.h */
typedef int (*callback)(int, int);
void insertion_sort(int *array, int n, callback comparison);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/* insertion_main.c */
#include<stdio.h>
#include<stdlib.h>
#include"insertion_sort.h"
int ascending(int a, int b)
{
    return a > b;
}
int descending(int a, int b)
{
    return a < b;
}
int even_first(int a, int b)
{
    /* code goes here */
}
int odd_first(int a, int b)
{
    /* code goes here */
}
int main(void)
{
    int i;
    int choice;
    int array[10] = {22,66,55,11,99,33,44,77,88,0};
    printf("ascending 1: descending 2: even_first 3: odd_first 4: quit 5\n");
    printf("enter your choice = ");
    scanf("%d",&choice);
    switch(choice)
    {
        case 1:
            insertion_sort(array,10, ascending);
            break;
        case 2:
            insertion_sort(array,10, descending);
         case 3:
            insertion_sort(array,10, even_first);
            break;
        case 4:
            insertion_sort(array,10, odd_first);
            break;
        case 5:
            exit(0);
        default:
            printf("no such option\n");
    }
    printf("after insertion_sort\n");
    for(i=0;i<10;i++)
        printf("%d\t", array[i]);
    printf("\n");
     return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* insertion_sort.c */
#include"insertion_sort.h"
void insertion_sort(int *array, int n, callback comparison)
{
    int i, j, key;
    for(j=1; j<=n-1;j++)
    {
        key=array[j];
        i=j-1;
        while(i >=0 && comparison(array[i], key))
        {
            array[i+1]=array[i];
            i=i-1;
        }
        array[i+1]=key;
    }
}

This concludes this article about function pointers and callbacks in C.
If you have any questions or comments about this article please leave it and we’ll answer it as soon as possible.
If you have any question leave it on our facebook page using this hashtag‪#‎embeddedx_knowledge_sharing  and stay tuned.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s