If a parameter is a function pointer, the caller can pass the address of a function to the implementer to call it. This is called a callback function ). For exampleqsort(3)
Andbsearch(3)
.
Callback Function example:void func(void (*f)(void *), void *p);
The following is a simple example. Implementsrepeat_three_times
Function, which can execute any callback function sent from the caller three times in a row.
Example 24.7. Callback Function
/* para_callback.h */#ifndef PARA_CALLBACK_H#define PARA_CALLBACK_Htypedef void (*callback_t)(void *);extern void repeat_three_times(callback_t, void *);#endif/* para_callback.c */#include "para_callback.h"void repeat_three_times(callback_t f, void *para){ f(para); f(para); f(para);}/* main.c */#include <stdio.h>#include "para_callback.h"void say_hello(void *str){ printf("Hello %s\n", (const char *)str);}void count_numbers(void *num){ int i; for(i=1; i<=(int)num; i++) printf("%d ", i); putchar('\n');}int main(void){ repeat_three_times(say_hello, "Guys"); repeat_three_times(count_numbers, (void *)4); return 0;}
Let's review the examples in the previous sections. The parameter types are defined by the implementer. In this example, the types of callback function parameters are defined by the caller.void *
Pointer. The implementer is only responsible for transferring the pointer to the callback function, regardless of the Data Type it actually points. The caller knows that the parameter ischar *
In the callback function provided by the user, you should know that the parameter is to be convertedchar *
Type.
A typical application of callback functions is to implement generic algorithms (generics algorithm) similar to C ++ ). The following implementationmax
A function can find the maximum value in any group of objects. It can be a group of objects.int
, A groupchar
Or a group of struct, but the implementer does not know how to compare the sizes of the two objects. The caller needs to provide a callback function for the comparison operation.
Example 24.8. Generic Algorithm
/* generics.h */#ifndef GENERICS_H#define GENERICS_Htypedef int (*cmp_t)(void *, void *);extern void *max(void *data[], int num, cmp_t cmp);#endif/* generics.c */#include "generics.h"void *max(void *data[], int num, cmp_t cmp){ int i; void *temp = data[0]; for(i=1; i<num; i++) { if(cmp(temp, data[i])<0) temp = data[i]; } return temp;}/* main.c */#include <stdio.h>#include "generics.h"typedef struct { const char *name; int score;} student_t;int cmp_student(void *a, void *b){ if(((student_t *)a)->score > ((student_t *)b)->score) return 1; else if(((student_t *)a)->score == ((student_t *)b)->score) return 0; else return -1;}int main(void){ student_t list[4] = {{"Tom", 68}, {"Jerry", 72}, {"Moby", 60}, {"Kirby", 89}}; student_t *plist[4] = {&list[0], &list[1], &list[2], &list[3]}; student_t *pmax = max((void **)plist, 4, cmp_student); printf("%s gets the highest score %d\n", pmax->name, pmax->score); return 0;}
max
The key for a function to operate a group of any types of objects is to passmax
Is an array composed of pointers to objects, rather than an array composed of objects.max
You don't have to worry about the object type. You just need to forward it to the comparison function.cmp
And then perform corresponding operations based on the comparison results,cmp
The callback function provided by the caller. The caller knows the object type and how to compare it.
The callback function in the preceding example is synchronously called and called by the caller.max
Function,max
Call a function.cmp
Function, which is equivalent to the callback function provided by the caller indirectly. In the actual system, asynchronous calling is also a typical usage of callback functions. The caller first transmits the callback function to the implementer. The implementer remembers this function, which is calledRegisterA callback function. when an event occurs, the implementer calls the previously registered function. For examplesigaction(2)
Register a signal processing function. When a signal is generated, the system calls this function for processing.pthread_create(3)
Register a thread function. When scheduling occurs, the system switches to the newly registered thread function for running. asynchronous callback functions are also widely used in Gui programming, for example, register a callback function for a button and call it when you click the button.
The following is a code framework.
/* registry.h */#ifndef REGISTRY_H#define REGISTRY_Htypedef void (*registry_t)(void);extern void register_func(registry_t);#endif/* registry.c */#include <unistd.h>#include "registry.h"static registry_t func;void register_func(registry_t f){ func = f;}static void on_some_event(void){ ... func(); ...}
Since the parameter can be a function pointer and the return value can also be a function pointerfunc()();
Such a call. Functions that return functions are rare in C language and common in some functional programming languages (such as LISP). The basic idea is to operate functions as data, input, output, and involved in operations. The operation function is called a high-order function ).
Article from: http://learn.akae.cn/media/ch24s05.html