1. 程式人生 > >函式指標-如何理解typedef void (*pfun)(void)

函式指標-如何理解typedef void (*pfun)(void)

問題:

在剛接觸typedef void (*pfun)(void) 這個結構的時候,存在疑惑,為什麼typedef後只有一“塊”東西,而不是兩“塊”東西呢?那是誰“替代”了誰啊?我總結了一下,一方面是對typedef的概念不清晰,另一方面受了#define的影響,犯了定向思維的錯誤。

概念理解:

  • typedef 只對已有的型別進行別名定義,不產生新的型別;

  • #define 只是在預處理過程對程式碼進行簡單的替換。

清晰瞭解兩個概念後,發現它們就是兩個不同的概念,並沒有太多的聯絡。

類比理解:

typedef  unsigned int
UINT32; // UINT32 型別是unsigned int UINT32 sum; // 定義一個變數:int sum; typedef int arr[3]; // arr 型別是 int[3];(存放int型資料的陣列) arr a; // 定義一個數組:int a[3];

同理:

typedef  void (*pfun)(void);         // pfun 型別是 void(*)(void)

pfun main;                          // 定義一個函式:void (*main)(void);

在部落格上看到一個經典的函式指標用例:

#include<stdio.h>

typedef int (*FP_CALC)(int, int);

//注意這裡不是函式宣告而是函式定義,它是一個地址,你可以直接輸出add看看

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
b? a/b : -1; } //定義一個函式,引數為op,返回一個指標。該指標型別為 擁有兩個int引數、 //返回型別為int 的函式指標。它的作用是根據操作符返回相應函式的地址 FP_CALC calc_func(char op) { switch (op) { case '+' : return add; // 返回函式的地址 case '-' : return sub; case '*' : return mul; case '/' : return div; default: return NULL; } return NULL; } //s_calc_func為函式,它的引數是 op,返回值為一個擁有兩個int引數、返回型別為int 的函式指標 int (*s_calc_func(char op)) (int, int) { return calc_func(op); } //終端使用者直接呼叫的函式,該函式接收兩個int整數,和一個算術運算子,返回兩數的運算結果 int calc(int a, int b, char op) { FP_CALC fp = calc_func(op); // 根據預算符得到各種運算的函式的地址 int (*s_fp)(int, int) = s_calc_func(op); // 用於測試 // ASSERT(fp == s_fp); // 可以斷言這倆是相等的 if (fp){ return fp(a, b); //根據上一步得到的函式的地址呼叫相應函式,並返回結果 } else{ return -1; } } void main() { int a = 100, b = 20; printf("calc(%d, %d, %c) = %d\n", a, b, '+', calc(a, b, '+')); printf("calc(%d, %d, %c) = %d\n", a, b, '-', calc(a, b, '-')); printf("calc(%d, %d, %c) = %d\n", a, b, '*', calc(a, b, '*')); printf("calc(%d, %d, %c) = %d\n", a, b, '/', calc(a, b, '/')); }

結合程式碼理解:

程式碼作者在註釋中表述得很清楚,個人覺得最有意思就是一下這個函式:

FP_CALC calc_func(char op) <–> int (*calc_func(char op)) (int, int)

程式碼作者試圖在斷言中說明這個關係,相比較,還是FP_CALC calc_func(char op)函式更能表達編碼者的意圖:calc_func函式返回FP_CALC型別的指標,是一個函式指標,這個函式的形式是int (函式名)(int, int),程式碼中int add(int a, int b)、int sub(int a, int b)…正是這樣的格式。

在閱讀《C和指標》的時候,我猛然想起還有一個東西叫“函式指標陣列”,也就是書中所描述的新概念:轉移表。

下面是實現一個簡易計算器的核心程式碼:

switch(oper){
  case ADD:
    result = add(oper1, oper2);
    break;

  case SUB:
    result = sub(oper1, oper2);
    break;

  case MUL:
    result = mul(oper1, oper2);
    break;

  case DIV:
    result = div(oper1, oper2);
    break;
  ……
}

這是一種我們常用的實現方式,在書中提到有一個最起碼看起來更高階,更簡潔的方法:

double add(double, double);
double sub(double, double);
double mul(double, double);
double div(double, double);
……
Double (*oper_fun[])(double, double) = {add, sub,mul,div,};
// 呼叫時:
result = oper_func[oper](oper1, oper2);

為什麼要呼叫函式來執行這些操作呢?把具體操作和選擇操作的程式碼分開是一種良好的設計方案。

更多參考