**回調函數** = 通過函數指針調用的函數。當你把一個函數的地址作為參數傳給另一個函數,並在後者內部通過該指針調用前者時,這個被調用的函數就是回調函數。
| 概念 | 聲明示例 | 含義 |
|---|---|---|
| 普通函數 | int func(int x); | 返回 int 的函數 |
| 指針函數 | int* func(int x); | 返回 int* 的函數 |
| 函數指針 | int (*fp)(int x); | 指向「接受 int、返回 int 的函數」的指針變量 |
代碼區同樣佔用內存,有首地址。fp = func; 將函數入口地址賦給指針,隨後可通過 fp(args) 調用。
qsort 接受比較函數指針,實現任意類型排序。SetTimer、信號處理、GUI 事件循環、網絡 I/O 完成通知。[c]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 回調函數類型:比較兩個 void* 元素 */
typedef int (*CompFunc)(void* ctx, void* a, void* b);
/* 通用冒泡排序:對 void** 數組排序 */
int bubble_sort(void** array, int len, CompFunc cmp, void* ctx) {
if (!array || !cmp) return -1;
for (int i = len - 1; i > 0; i--) {
for (int j = 1, max = 0; j <= i; j++) {
if (cmp(ctx, array[j], array[max]) > 0) max = j;
if (max != i) {
void* tmp = array[max];
array[max] = array[i];
array[i] = tmp;
}
}
}
return 0;
}
/* 升序比較器 */
int cmp_asc(void* ctx, void* a, void* b) {
return *(int*)a - *(int*)b;
}
/* 降序比較器 */
int cmp_desc(void* ctx, void* a, void* b) {
return *(int*)b - *(int*)a;
}
/* 測試 */
int main() {
int n = 10;
void** arr = malloc(n * sizeof(void*));
int* data = malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
data[i] = rand() % 100;
arr[i] = &data[i];
printf("%d ", data[i]);
}
puts("");
bubble_sort(arr, n, cmp_asc, NULL);
for (int i = 0; i < n; i++) printf("%d ", *(int*)arr[i]);
puts("");
bubble_sort(arr, n, cmp_desc, NULL);
for (int i = 0; i < n; i++) printf("%d ", *(int*)arr[i]);
puts("");
free(arr); free(data);
return 0;
}
qsort, bsearch, pthread_create)。std::function。僅在對接 C 庫、舊有回調接口時使用函數指針回調。FreeRDP 將所有繪圖操作抽象為回調接口(rdpGraphics)。移植到新圖形庫(如 Skia)時,只需實現這些回調函數並註冊,**無需理解整個 RDP 協議流程**,極大降低了移植複雜度。這正是「面向接口編程」+「依賴倒置」的經典體現。
回調函數本質是將「做什麼」與「怎麼做」分離。掌握函數指針語法、理解調用約定、設計清晰的回調原型(含上下文指針 void* ctx 傳遞狀態),是系統級 C 開發的核心技能。