如何理解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);

 

 

在博客上看到一個經典的函數指針用例:

為保護原創作者的權益,以下例子代碼不作修改:

<來源網址:http://www.cnblogs.com/shenlian/archive/2011/05/21/2053149.html>

 

#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)…正是這樣的格式。

 

 

 

 (修改於 2016-12-22  19:23:37)

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

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

 1 switch(oper){  2   case ADD:  3     result = add(oper1, oper2);  4     break;  5 
 6   case SUB:  7     result = sub(oper1, oper2);  8     break;  9 
10   case MUL: 11     result = mul(oper1, oper2); 12     break; 13 
14   case DIV: 15     result = div(oper1, oper2); 16     break; 17   …… 18 }

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

1 double add(double, double); 2 double sub(double, double); 3 double mul(double, double); 4 double div(double, double); 5 …… 6 Double (*oper_fun[])(double, double) = {add, sub,mul,div,…}; 7 調用時: 8 result = oper_func[oper](oper1, oper2);

 

為什么要調用函數來執行這些操作呢?把具體操作和選擇操作的代碼分開是一種良好的設計方案。

——《C和指針》

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM