函數指針指向代碼區,而普通指針指向數據區。掌握函數指針是實現回調、狀態機、插件架構、面向對象模擬的關鍵。本文從語法解析到實戰模式全覆蓋。
返回類型 (*指針變量名)(參數列表);
例子:void (*pf)(void); — 指向 void f(void) 類型函數。
void open() { puts("open"); }
void print() { puts("print"); }
void exit() { puts("exit"); }
void (*pfs[3])() = { open, print, exit }; // 函數指針數組
int main() {
void (*pf)() = open; // pf 指向 open
pf(); // 調用 open()
for (int i=0; i<3; ++i) pfs[i](); // 依次調用三個函數
}
關鍵:open、&open、*open 在調用上下文中等價,均為函數入口地址。
| 聲明 | 含義 | 拆解步驟 |
|---|---|---|
void (*getInterrupt(int))(); | 函數 getInterrupt 接收 int,返回 void(*)() | 1. getInterrupt 是函數 2. 參數 int 3. 返回指針 4. 指向 void() |
void setInterrupt(int, void (*pf)()); | 函數 setInterrupt,第二參數是函數指針 | pf 是指針 → 指向 void() |
LRESULT (*lpfnWndProc)(HWND, UINT, WPARAM, LPARAM); | 變量 lpfnWndProc 是函數指針 | 指向 LRESULT (HWND, UINT, WPARAM, LPARAM) |
typedef void (*Callback)(int status, void* userdata);
void async_operation(Callback cb, void* ud) {
// ... 異步工作 ...
cb(0, ud); // 完成後回調
}
void my_handler(int s, void* ud) { printf("Done: %d\n", s); }
async_operation(my_handler, NULL);
typedef struct {
void (*init)(void*);
int (*process)(void*, int);
void (*cleanup)(void*);
} PluginOps;
PluginOps my_plugin = { my_init, my_process, my_cleanup };
// 運行時動態加載插件,賦值 my_plugin.process = new_process;
int cmp_int(const void* a, const void* b) {
return *(const int*)a - *(const int*)b;
}
qsort(arr, n, sizeof(int), cmp_int);
void handler(int sig) { /* ... */ }
signal(SIGINT, handler); // handler 類型 void (*)(int)
void (*pf)(int) 不能指向 void f(float),嚴格按類型檢查。__stdcall/__cdecl 不可混用,需在指針類型中聲明:void (__stdcall *pf)(int)。void (*get_handler(int))(int);。void (*p[3])() 是函數指針數組;void *p[3] 是 void* 數組。typedef void (*FuncPtr)(int, int);
FuncPtr p = my_func; // 清晰易讀
FuncPtr table[10]; // 數組聲明直觀
函數指針是 C 語言實現多態、回調、動態分發的核心機制。熟練掌握 返回類型 (*名)(參數) 語法,善用 typedef 化解複雜聲明,結合函數指數組/結構體構建虛表,即可在純 C 中實現靈活的組件化架構。