在 C 裏面,可以用 typedef 來爲一個已有的數據類型增加一個新的別名。比如:
typedef int Length;
這種簡單的形式,大家都能理解。可是遇到下面這種形式,不少人就傻眼了。比如:
typedef int (*PFI)(int, const char *);
難道是把 int 數據類型定義成了 (*PFI)(int, const char *)
的數據類型,可是哪有這樣的數據類型啊。即使被別人告知這是定義了一種函數指針類型,但卻怎麼也無法和 typedef int Length 這種形式關聯起來,不是應該有一種已有的數據類型,一種新的數據類型嗎?可是它們在哪呢?
我們把上面的表達式稍做改變,疑惑就解開了,如下:
typedef int (int, const char *) * PFI;
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~
原來的數據類型 別名
或者:
typedef int (int, const char *) *PFI;
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~
原來的數據類型 別名
所以,這個表達式是定義了類型爲 PFI 的函數指針類型,指向的函數,返回值是 int 型,形參是 int 和 const char *
。所以,它的使用就很好理解了,比如:
//測試代碼,所以沒有寫得很嚴謹
int str_chr(int index, const char *s)
{
return s[index];
}
...
PFI funp = &str_chr;
//對於函數指針,這裏也直接寫成 PFI funp = str_chr; 上面那種寫法很少用
int ret = (*funp)(5, "baurine");
//對於函數指針,也可以直接寫成 int ret = funp(5, "test");
也可以不將 PFI 定義成函數指針類型,而是直接定義成函數類型,如下:
typedef int PFI(int, const char *);
那麼它就要這麼使用:
PFI *funp = str_chr;
這就是 C 語言的靈活和複雜之處。
來看一個更復雜的吧 (與 typedef 無關了):
void (*signal(int signo, void (*func)(int)))(int);
是不是要瘋了…至少第一次看到這種定義的時候,我是的。這是 Unix/Linux 裏系統調用 signal 函數的原型。這樣的定義怎麼來理解呢,同樣,我們來做一下調整,如下:
void (int) * signal(int signo, void (int) *func);
~~~~~~~~~~~~~ ~~~~~~ ~~~~~~~~~ ~~~~~~~~~~~~~~~~~
返回值類型 函數名 形參一 形參二
所以,首先這個表達式是定義了一個函數,函數名是 signal,形參一是 int 型,返回值和形參二的類型是一樣的,都是函數指針,指向的函數,返回值是 void,形參是 int 型。呃,是不是很繞。
signal 函數的作用就是爲某個信號註冊一個新的信號處理函數,同時返回原來的信號處理函數,以便在退出時進行恢復。
上面的定義形式實在是不是太複雜了,所以 man 手冊上實際上是這麼定義的:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
啊,你問我爲什麼上面那些表達式可以做那樣的調整呢,說實話,我也不知道,我只知道這樣調整後就可以方便理解了。我也沒查到哪裏有這方面的文檔,如果有人知道的話,能否告之。
轉自:https://baurine.github.io/2013/03/18/understand_typdef_funp.html