() (函數)、[] (數組) 則說明「是...函數/數組」。),轉向**左**看:遇到 * 則說明「指向...的指針」。() 組,作為整體跳出,繼續右左循環。| 優先級 | 運算符 | 結合性 | 含義 |
|---|---|---|---|
| 1 (最高) | () (函數調用), [] (下標) | 左→右 | 函數、數組修飾符 |
| 2 | * (指針聲明) | 右→左 | 指針修飾符 |
| 3 | 基礎類型 | - | int, float, struct... |
口訣:先右後左,括號優先,* 最後。
| 聲明 | 拆解步驟 | 最終含義 |
|---|---|---|
int (*fp)(int, char); | fp → 右 () → 左 * → 右 (int,char) → 左 int | fp 是指針,指向函數,參數 (int, char),返回 int |
int (*fp[5])(int); | fp → 右 [5] → 左 * → 右 (int) → 左 int | fp 是數組[5],元素是指針,指向函數(參數 int)返回 int |
int *(*fp)(int); | fp → 右 () → 左 * → 右 (int) → 左 * → 左 int | fp 是指針,指向函數(參數 int)返回 int* |
int (*(*fp)(int))[5]; | fp → 右 () → 左 * → 右 (int) → 左 * → 右 [5] → 左 int | fp 是指針,指向函數(參數 int)返回 指向 int[5] 的指針 |
int (*fp(int))[5]; | fp → 右 (int) → 左 * → 右 [5] → 左 int | fp 是函數(參數 int)返回 指向 int[5] 的指針 |
void (*signal(int, void (*)(int)))(int); | signal → 右 (int, ...) → 左 * → 右 (int) → 左 void | signal 是函數(參數 int, 函數指針)返回 函數指針(參數 int)返回 void |
// 1. 定義函數指針類型 typedef int (*CompareFunc)(const void *, const void *); typedef void (*Callback)(void *ctx, int status); typedef void *(*AllocFunc)(size_t size, void *ctx); // 2. 使用類型別名聲明變量/參數 CompareFunc cmp = my_compare; Callback cb = my_callback; AllocFunc alloc = my_alloc; // 3. 函數參數極其清晰 void qsort_generic(void *base, size_t nmemb, size_t size, CompareFunc cmp); void register_cb(Callback cb, void *ctx); void *allocate(AllocFunc alloc, size_t n, void *ctx);
鐵律:複雜函數指針必須用 typedef,直接聲明僅用於簡單場景。
typedef void (*EventHandler)(int event_id, void *data, void *user_ctx);
struct EventLoop {
EventHandler handlers[MAX_EVENTS];
void *user_ctx[MAX_EVENTS];
};
void event_loop_register(struct EventLoop *loop, int id, EventHandler h, void *ctx);
void event_loop_dispatch(struct EventLoop *loop, int id, void *data);
typedef struct AnimalVTable {
void (*speak)(void *self);
void (*move)(void *self, int dx, int dy);
void (*destroy)(void *self);
} AnimalVTable;
typedef struct Animal {
const AnimalVTable *vptr;
// 具體數據...
} Animal;
void animal_speak(Animal *a) { a->vptr->speak(a); }
// 繼承:Dog 定義自己的 vtable,構造時指向它
typedef int (*CmpFunc)(const void *, const void *); void generic_sort(void *base, size_t n, size_t sz, CmpFunc cmp); void *generic_find(const void *key, const void *base, size_t n, size_t sz, CmpFunc cmp);
// 插件導出表
typedef struct PluginAPI {
const char *name;
int version;
int (*init)(void *host_api);
void (*shutdown)(void);
void (*process)(void *data);
} PluginAPI;
// 主程序加載
typedef PluginAPI *(*GetPluginAPI)(void);
void *handle = dlopen("plugin.so", RTLD_NOW);
GetPluginAPI get_api = dlsym(handle, "get_plugin_api");
PluginAPI *api = get_api();
int (*fp)(int, int); 與 int (*fp)(int a, int b); 等價,但保留參數名利於文檔。int *fp(int); 是函數返回 int*;int (*fp)(int); 才是指針。**括號決定一切**。void foo(int arr[10]); 實際是 void foo(int *arr);。函數指針同理:void (*fp)(int arr[10]); 等價 void (*fp)(int *);。ptype fp 顯示完整類型;Clang __builtin_dump_type(fp) 編譯期輸出。assignment from incompatible pointer type 多為指針層級、參數類型、返回類型不匹配,逐層對照 typedef 定義。// C++11+ std::functionfp = [](int a, int b) { return a + b; }; auto cmp = [](const void *a, const void *b) { ... }; std::sort(vec.begin(), vec.end(), cmp); // 模板推導,無需函數指針
C++ 提供類型安全、捕獲上下文、內聯優化優勢,但 C 風格函數指針在 ABI 穩定、C 互操作、嵌入式無標準庫、動態加載插件 場景不可替代。
掌握右左法則、操作符優先級、typedef 封裝、實戰模式 (回調、虛表、泛型算法、插件),能輕鬆讀寫任意複雜的 C 函數指針聲明。核心心法:**從標識符出發,螺旋向外,遇括號跳轉,typedef 隔離複雜度**。這是系統級 C 程序員的必備硬功夫。