void func(void (*f)(void *), void *p);
調用者 | 實現者 |
---|---|
|
|
repeat_three_times
函數,能夠把調用者傳來的任何回調函數連續執行三次。
/* para_callback.h */ #ifndef PARA_CALLBACK_H #define PARA_CALLBACK_H typedef 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; }
void *
指針,實現者只負責將這個指針轉交給回調函數,而不關心它到底指向什麼數據類型。調用者知道本身傳的參數是
char *
型的,那麼在本身提供的回調函數中就應該知道參數要轉換成
char *
型來解釋。
max
函數能夠在任意一組對象中找出最大值,能夠是一組
int
、一組
char
或者一組結構體,可是實現者並不知道怎樣去比較兩個對象的大小,調用者須要提供一個作比較操做的回調函數。
/* generics.h */ #ifndef GENERICS_H #define GENERICS_H typedef 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
函數之因此能對一組任意類型的對象進行操做,關鍵在於傳給
max
的是指向對象的指針所構成的數組,而不是對象自己所構成的數組,這樣
max
沒必要關心對象究竟是什麼類型,只需轉給比較函數
cmp
,而後根據比較結果作相應操做便可,
cmp
是調用者提供的回調函數,調用者固然知道對象是什麼類型以及如何比較。
max
函數,
max
函數則調用
cmp
函數,至關於調用者間接調了本身提供的回調函數。在實際系統中,異步調用也是回調函數的一種典型用法,調用者首先將回調函數傳給實現者,實現者記住這個函數,這稱爲
註冊一個回調函數,而後當某個事件發生時實現者再調用先前註冊的函數,好比
sigaction(2)
註冊一個信號處理函數,當信號產生時由系統調用該函數進行處理,再好比
pthread_create(3)
註冊一個線程函數,當發生調度時系統切換到新註冊的線程函數中運行,在GUI編程中異步回調函數更是有廣泛的應用,例如爲某個按鈕註冊一個回調函數,當用戶點擊按鈕時調用它。
/* registry.h */ #ifndef REGISTRY_H #define REGISTRY_H typedef 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(); ... }
func()();
這樣的調用。返回函數的函數在C語言中不多見,在一些函數式編程語言(例如LISP)中則很常見,基本思想是把函數也看成一種數據來操做,輸入、輸出和參與運算,操做函數的函數稱爲高階函數(High-order Function)
。