Programmers can find the address of any named component in a C++ program, including functions, and save the address in a pointer variable. This section demonstrates function pointers with a programming technique called callback functions. In this context, programs pass one function as an argument to another, suggesting that the technique involves three functions: the function passing the function pointer, the function receiving the pointer, and the function referenced by the pointer. To clarify the following discussion, we'll call the passing or sending function the client, the passed or referenced function the callback function or simply the callback, and the receiving function the server.
Programmers divide callback functions into two categories. We explore a simple example of an asynchronous callback here, and a synchronous callback in the strings chapter (qsort and bsearch). A function's name represents its address or entry point (the address of the first machine instruction executed when a program calls the function). The following pseudo code illustrates the relationship between the three functions:
void callback() { ... }
. . .
client() { ...; server(callback); ... }
In the case of an asynchronous callback, the client registers or "remembers" the callback's address, allowing it to call the function later, possibly after being triggered by some event. The most challenging aspect of working with function pointers is understanding the syntax necessary for defining appropriate pointer variables.
In contrast to simple pointers, defining function pointers involves two pairs of parentheses. Although the characters are the same for both pairs, the operators they represent are not. Understanding the purpose of the different operators is crucial for understanding the definition syntax.
| Prerequisite Concepts | Function Pointer Variable Definition |
|---|---|
|
return-type (*function)(parameter-list); |
In the context of callback functions, the server function is responsible for defining the pointer variable parameter. In this example, the atexit library function fulfills this task, making it surprisingly easy to use. The atexit function allows programmers to register at least 32 asynchronous callback functions (some implementations allow more). The program runs the callbacks when the program terminates, either by calling the exit function or by returning from main. The program calls the functions in the reverse order of their registration - the first function registered is the last function called. One possible use for atexit is to register one or more "clean up" functions. For example, the program may create some temporary files that it should remove as part of its termination.
atexit restricts the registered functions, requiring a void return type and disallowing any parameters, but does not restrict the code in the function bodies. Other server functions may have different requirements.
| The callback function | The server and its parameter | Calling the server |
|---|---|---|
void func()
{
. . .
} |
atexit(func); |
int atexit( void (*f)() ); |
| (a) | (b) | (c) |
#include <iostream>
#include <stdlib.h> // for the atexit prototype
using namespace std;
void test1()
{
cout << "Test 1\n";
}
void test2()
{
cout << "Test 2\n";
}
int main()
{
atexit(test1);
atexit(test2);
cout << "main is done\n";
return 0;
}
main is done Test 2 Test 1
The previous examples illustrate the general client-side operations using a library server function, and demonstrate them with the atexit function. However, they fail to demonstrate the syntax the server uses to call the referenced or passed callback function. Programmers can also write application-specific server functions that, like atexit, require one or more function-pointer arguments. Fortunately, calling a passed function is unexpectedly simple, as illustrated by the following pseudo code.
int my_callback(int x)
{
. . .
} |
function(10, my_callback); |
void function(int a, int (*cb)(int))
{
cb(a);
} |
| (a) | (b) | (c) and (d) |
cb, as a pointer to a function returning an integer and requiring an integer argument.