C語言中 typedef 定義的函數指針

在 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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章