Skip to content

C Function Pointer 基礎用法整理

davidlei

最近在讀 jserv 老師的 Linux 核心設計講座,由於之前比較少寫 C,對 function pointer 只有模糊的概念,從來沒有認真用過,趁這個機會寫個筆記好好整理一下。

之後在學習過程中遇到 function pointer 的應用,也會一併補充到這篇文章中。

function pointer

function pointer 顧名思義就是指向某個 function 的 pointer。有了 function pointer,就可以把 function 當作參數傳入另一個 function,讓程式設計更有彈性,也可以減少大量的 if/elseswitch case

先從一個簡單的 function pointer 宣告開始:

int (*myFunc)(int, int);

這是一個基本的 function pointer 宣告,myFunc 是一個指標,指向一個 function:

假設有個 function 宣告成以下形式:

void parseFunc(float f1, int i1, char c1);

對應的 function pointer 宣告如下:

void (*myFunc)(float, int, char);

解讀:myFunc 是一個指標,指向一個接受 floatintchar 三個參數並回傳 void 的 function。

來驗證看看這個 function pointer 是否真的能呼叫 parseFunc

#include <stdio.h>

void parseFunc(float f1, int i1, char c1) {
    printf("%f %d %c\n", f1, i1, c1);
}

int main() {
    parseFunc(0.87, 87, 'a');

    void (*myFunc)(float, int, char) = parseFunc;
    myFunc(0.87, 877, 'b');
    return 0;
}

程式執行結果

注意

宣告 function pointer 時需要注意,*myFunc 必須用括號包起來:

void (*myFunc)(float, int, char)

這個括號不能省略,省略之後就不是 function pointer 的宣告了,而是:

void *myFunc(float, int, char);

這樣 myFunc 就不是 function pointer,而是單純宣告了一個回傳 void* 的 function。

Jserv 上課的範例

看完基礎的例子,來試試 jserv 在 你所不知道的C語言:指標篇 開頭舉出的範例:

試著自己解釋這個宣告的意思:

void **(*d) (int &, char **(*)(char *, char **));

應用舉例

假設要寫一個 calculate function,它接受三個參數:

傳入 ab 之後再傳入計算方式,就可以用 function pointer 取代 switch/case,大幅提升可讀性:

我們可以宣告成

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div(int a, int b) { return a / b; }

int calculate(int a, int b, int (*cal)(int, int));

這樣就可以把實現好的加減乘除 function 當作參數傳入 calculate

不過 calculate 第三個參數的宣告還是有點囉嗦,可讀性還有改善空間。這時候可以用 typedef 幫常用的 function pointer 宣告取一個簡短的名稱:

typedef int (*calc)(int, int);

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div(int a, int b) { return a / b; }

int calculate(int a, int b, calc method) 
{
    return method(a, b);
}

這樣在看 calculate 的宣告時,一眼就能知道第三個參數是要傳入指定的運算方法。

完整的程式碼放在 GitHub,把 code 載下來自己跑一次,順便改改看寫法,觀察其中的差異。

reference

Edit this post
Previous
golang cobra: 在沒有添加任何參數的情況下預設產生 help message
Next
使用 Hugo 主題 LoveIt 架設 blog 資源紀錄