Contents

C Function Pointer 基礎用法整理

這最近在看 jserv 大神的 linux 核心設計講座,因為之前比較少寫 c,所以對於 function pointer 只有一點概念但沒有真正寫過,所以趁這個機會寫個筆記來紀錄一下用法。

之後在學習的過程中如果遇到 function pointer 的應用也會一併整理在這篇文章中。

function pointer

function pointer 顧名思義就是指向某個 functionpointer,有了 function pointer 我們就可以實現把 function 當作參數,傳進一個 function 之中,或者更加彈性的設計我們的程式,減少多餘的 if/else, switch case

我們先從一個簡單的 function pointer 宣告開始講起

int (*myFunc)(int, int);

上面就是一個基本的 function pointer 宣告

一個 function pointer 變數名稱為 myFunc,可以這麼解讀

  • myFunc 是一個指標指向一個 function
    • function 有兩個 int 的 parameters
    • function 會回傳 int

假設今天我有個 function 宣告成以下這種形式

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

我們要怎麼宣告一個 pointer 去指向這個 function 呢?

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

解讀成

  • myFunc 是一個指標指向一個 function
    • function 有三個 parameters,分別要傳入
      • float
      • int
      • char
    • function 會回傳 void

所以我們可以來驗證看看這個 function pointer 是否能真的呼叫 parseFunc 這個 function

#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 的時候

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

會注意到 *myFunc 會用括號包起來,這是不能省略的喔,省略的話就不是 function pointer 的宣告方法了。

省略的話會變成

void *myFunc(float, int, char);

這樣子 myFunc 就不是 function pointer 了,而是單純宣告一個 function

Jserv 上課的範例

簡單的例子看完就可以來看看 Jserv你所不知道的C語言:指標篇 開頭所舉出來的範例

試試看能不能自己寫出該宣告怎麼解釋

void **(*d) (int &, char **(*)(char *, char **));
  • d 是一個 function pointer, 該 function 有兩個 parameters
    • 第一個 parameters: a reference to an int
    • 第二個 parameters: 同樣也是一個 function pointer
      • function 有兩個 parameters
        • a pointer to a char
        • a pointer to a pointer to a char
      • return a pointer to a pointer to a char
  • return a pointer to a pointer to void

應用舉例

今天如果我想寫一個 calculatefunction 該 function 有三個參數

  • a
  • b
  • 加減乘除

傳入 a, b 之後再傳入要計算的動作,我們可以利用 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 之後我們可以寫成以下的形式

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 宣告的時候就會清楚的知道第三個參數要把指定的 method 傳進去。

完整的程式碼我放在 GitHub,可以把 code 載下來自己 run 一次,順便改改看寫法,觀察其中的不同。

reference