<legend id="yqiqe"><i id="yqiqe"></i></legend>
  • <span id="yqiqe"><sup id="yqiqe"><nav id="yqiqe"></nav></sup></span>
    <acronym id="yqiqe"><sup id="yqiqe"></sup></acronym>
    <ol id="yqiqe"></ol>
  • <input id="yqiqe"></input>

  • <optgroup id="yqiqe"></optgroup>

      <span id="yqiqe"></span>
        1. <dd id="yqiqe"><output id="yqiqe"></output></dd>

          您好, 登錄| 注冊|
          論壇導航
          您好, 登錄| 注冊|
          子站:
          論壇首頁    單片機MCU/嵌入式
          •  發帖
          • 收藏

          函數指針作為某個函數的參數及定義函數指針(回調函數)
          閱讀: 1665 |  回復: 5 樓層直達

          2019/07/17 17:30:23
          1
          lihui710884923[實習版主]
          電源幣:471 | 積分:1 主題帖:151 | 回復帖:498
          LV8
          師長

          QQ截圖20160321155901 內容精選】管理員精心選擇的優質內容 快來討論吧


          一、 定義某一函數的指針類型:就像自定義數據類型一樣,我們也可以先定義一個函數指針類型,然后再用這個類型來申明函數指針變量。我先給你一個自定義數據類型的例子。

          typedef int* PINT;    //為int* 類型定義了一個PINT的別名

          int main()

          { 

           int x;  

          PINT px=&x;   //與int * px=&x;是等價的。PINT類型其實就是int * 類型 

           *px=10;       //px就是int*類型的變量  

            return 0;

          }根據注釋,應該不難看懂吧!(雖然你可能很少這樣定義使用,但以后學習Win32編程時會經常見到的。)

          下面我們來看一下函數指針類型的定義及使用:(請與上對照!)

          //自行包含頭文件void MyFun(int x);    //此處的申明也可寫成:

          void MyFun( int );

          typedef void (*FunType)(int );   //這樣只是定義一個函數指針類型FunType FunP;             

           //然后用FunType類型來申明全局FunP變量int main(int argc, char* argv[]){//FunType FunP;    //函數指針變量當然也是可以是局部的 ,那就請在這里申明了。    MyFun(10);        FunP=&MyFun;     (*FunP)(20);          return 0;}void MyFun(int x)  {   printf(“%d\n”,x);}看黑體部分:首先,在void (*FunType)(int ); 前加了一個typedef 。這樣只是定義一個名為FunType函數指針類型,而不是一個FunType變量。然后,FunType FunP;  這句就如PINT px;一樣地申明一個FunP變量。其它相同。整個程序完成了相同的事。這樣做法的好處是:有了FunType類型后,我們就可以同樣地、很方便地用FunType類型來申明多個同類型的函數指針變量了。如下:FunType FunP2;FunType FunP3;//……

          標簽 STM32 C語言
          2019/07/17 17:31:31
          2
          電源網-fqd
          電源幣:5059 | 積分:15079 主題帖:476 | 回復帖:5079
          LV11
          統帥
          關注關注,期待下面內容
          2019/07/17 17:33:36
          3
          lihui710884923[實習版主]
          電源幣:471 | 積分:1 主題帖:151 | 回復帖:498
          LV8
          師長

          二、 函數指針作為某個函數的參數
          既然函數指針變量是一個變量,當然也可以作為某個函數的參數來使用的。所以,你還應知道函數指針是如何作為某個函數的參數來傳遞使用的。
          給你一個實例:
          要求:我要設計一個CallMyFun函數,這個函數可以通過參數中的函數指針值不同來分別調用MyFun1、MyFun2、MyFun3這三個函數(注:這三個函數的定義格式應相同)。
          實現:代碼如下:
          //自行包含頭文件 
          void MyFun1(int x);  
          void MyFun2(int x);  
          void MyFun3(int x);  
          typedef void (*FunType)(int ); //②. 定義一個函數指針類型FunType,與①函數類型一至
          void CallMyFun(FunType fp,int x);

          int main(int argc, char* argv[])
          {
             CallMyFun(MyFun1,10);   //⑤. 通過CallMyFun函數分別調用三個不同的函數
             CallMyFun(MyFun2,20);   
             CallMyFun(MyFun3,30);   
          }
          void CallMyFun(FunType fp,int x) //③. 參數fp的類型是FunType。
          {
            fp(x);//④. 通過fp的指針執行傳遞進來的函數,注意fp所指的函數是有一個參數的
          }
          void MyFun1(int x) // ①. 這是個有一個參數的函數,以下兩個函數也相同
          {
             printf(“函數MyFun1中輸出:%d\n”,x);
          }
          void MyFun2(int x)  
          {
             printf(“函數MyFun2中輸出:%d\n”,x);
          }
          void MyFun3(int x)  
          {
             printf(“函數MyFun3中輸出:%d\n”,x);
          }
          輸出結果:略


          1. 函數指針是指向函數的指針變量。c在編譯時,每一個函數都有一個入口地址,該入口地址就是函數指針指向的地址處。有了指向函數的指針變量后。可以通過該指針變量調用函數,函數指針有兩個用途:調用函數、做函數的參數:

            1. 調用函數,如下所示:

          輸出結果如下:


          由以上可以說明成功調用。


             b.無參函數指針做參數的實現,如下(標準寫法)所示:


          輸出結果如下:


          還有以下寫法也能成功,因為c語言標準規定可以這樣用:

          也能成功輸出


          c.帶參有返回值的函數指針做參數的





          而不能寫成如下所示:

          也可寫成以下形式,其中涉及到函數指針類型的轉換:


          2.函數指針數組的實用之處:當我們需要判斷大量條件的時候,并且在每一個條件都有相應的處理函數,這時實用switch...case..的代碼量會很大,并且效率會比較低,這個時候就可以使用函數指針數組來解決這個問題了,可以使用每個條件為數組下表:如下所示:


          結果如下


          回調函數

           

          1、基礎知識

          所謂回調,就是模塊A要通過模塊B的某個函數b()完成一定的功能,但是函數b()自己無法實現全部功能,需要反過頭來調用模塊A中的某個函數a()來完成,這個a()就是回調函數。如下圖

           

          ①約定接口規范。在模塊B必須約定接口規范,也就是定義回調函數a()的函數原型


          一開始是不好理解,用下面這個例子可能會有幫助:

          諸葛亮(A)給趙子龍(B)一個錦囊(a()),吩咐他在干活時(b())若遇到危急時打開按錦囊(a())指示辦, 錦囊里的命令就是回調函數,危急時刻就是回調的時機。 

          不同的錦囊里可以有不同的命令。

          在看LWIP時,見到用回調函數,再看某老外公司OPC源代碼時,見到用回調函數。看我國內某些代碼(軟件等)時沒用到。于是,我對回調函數產生了很大的好奇。以前,我寫VC程序時用到過回調函數,但是沒有用C語言來使用。最近,看到國外大量的經典代碼中廣泛使用了回調函數(LWIP、某兩個公司的OPC程序等),都是C語言來實現的,而不是VC windows程序中別人實現自己使用的那種。

          為了弄明白這種函數的奧妙,首先提出三個問題:

          1.        回調函數是什么東西?

          2.        回調函數怎么開發,怎么使用?

          3.        回調函數的作用,應該在什么情況下使用?

           

          帶著問題來學習,有目的!呵呵,個人經驗。

          打開baidu.com、google.cn搜索了好多資料,如下:

          順便提一下,某君的一個簽名很讓我佩服:1好好活著,因為我們會死很久。2五千年的文明 兩百年的無奈

           

          第一個問題:

          *******************************************************************************

          其實回調就是一種利用函數指針進行函數調用的過程.  

          為什么要用回調呢?比如我要寫一個子模塊給你用,   來接收遠程socket發來的命令.當我接收到命令后,   需要調用你的主模塊的函數,   來進行相應的處理.但是我不知道你要用哪個函數來處理這個命令,     我也不知道你的主模塊是什么.cpp或者.h,   或者說,   我根本不用關心你在主模塊里怎么處理它,   也不應該關心用什么函數處理它......   怎么辦?

          使用回調!

          —— lone wolf

           

          使用回調函數實際上就是在調用某個函數(通常是API函數)時,將自己的一個函數(這個函數為回調函數)的地址作為參數傳遞給那個函數。而那個函數在需要的時候,利用傳遞的地址調用回調函數,這時你可以利用這個機會在回調函數中處理消息或完成一定的操作。

          —— 某專家

           

          回調函數,就是由你自己寫的。你需要調用另外一個函數,而這個函數的其中一個參數,就是你的這個回調函數名。這樣,系統在必要的時候,就會調用你寫的回調函數,這樣你就可以在回調函數里完成你要做的事。

          —— 綠葉

           

          http://hi.baidu.com/zhuyipeng/blog/item/863fefdb7c736c63d1164eec.html 是一篇比較好的文章。

           

          什么是回調函數?
            回調函數是應用程序提供給Windows系統DLL或其它DLL調用的函數,一般用于截獲消息、獲取系統信息或處理異步事件。應用程序把回調函數的地址指針告訴DLL,而DLL在適當的時候會調用該函數。回調函數必須遵守事先規定好的參數格式和傳遞方式,否則DLL一調用它就會引起程序或系統的崩潰。通常情況下,回調函數采用標準WindowsAPI的調用方式,即__stdcall,當然,DLL編制者可以自己定義調用方式,但客戶程序也必須遵守相同的規定。在__stdcall方式下,函數的參數按從右到左的順序壓入堆棧,除了明確指明是指針或引用外,參數都按值傳遞,函數返回之前自己負責把參數從堆棧中彈出。
            理解回調函數!

          —— jufengfeng

           

          Function Pointers provide the concept of callback functions.

          —— newty.de

          *******************************************************************************

          看了這么多的資料,我只將每位的定義總結一下就一句話:回調函數就是函數指針的一種用法。

          在部分資料上,大量討論了回調函數怎么被調用,到底被誰調用,還有好多的圖形,我認為都沒有看到問題的本質。

           

           

          第二個問題:

          *********************************************************************

          我實現了一個很簡單的回調函數。

          #include <stdio.h>

           

          void printWelcome(int len)

          {

                 printf("歡迎歡迎 -- %d/n", len);

          }

           

          void printGoodbye(int len)

          {

                 printf("送客送客 -- %d/n", len);

          }

           

          void callback(int times, void (* print)(int))

          {

                 int i;

                 for (i = 0; i < times; ++i)

                 {

                        print(i);

                 }

                 printf("/n我不知道你是迎客還是送客!/n/n");

          }

          void main(void)

          {

                 callback(10, printWelcome);

                 callback(10, printGoodbye);

                 printWelcome(5);

          }

          *******************************************************************************

          上面的代碼沒有被任何系統函數調用,說明那些東西只是撒撒土迷迷路人眼而已。還有面相對象編程時,用class給封裝起來也是掩人耳目,不要被外表所迷惑。

           

           

          第三個問題:

          *********************************************************************

          用過STL的人都知道,在STL中眾多算法和程序都用到回調函數,這實現了一種策略。只要任何符合我的標準的函數和計算都可以用我這個公式。你可以實現各種各樣的回調函數,只要符合我的格式就能用。

          就上面的程序來說,你只要函數格式符合cllback第二個參數的格式不論你給別人做飯、鋪床疊被都可以正常工作。這就是回調的作用,把回調實現留給別人。

          這是一個用法。

           

          有一位朋友用分層的概念來解釋了回調機制:callback函數為B層,main函數和print*函數為A層,A層調用了B層的回調函數callmeback,而B層的回調函數調用了A層的實現函數print*。說白了B層就是一個接口。

           

           

          這是我的理解。Over


          2019/07/17 17:49:39
          4
          電源網-fqd
          電源幣:5059 | 積分:15079 主題帖:476 | 回復帖:5079
          LV11
          統帥
          圖片看不到,重新上傳下吧
          2019/07/18 10:52:53
          5
          lihui710884923[實習版主]
          電源幣:471 | 積分:1 主題帖:151 | 回復帖:498
          LV8
          師長
          已上傳
          2019/07/18 10:54:26
          6
          電源網-fqd
          電源幣:5059 | 積分:15079 主題帖:476 | 回復帖:5079
          LV11
          統帥
          客服熱線
          服務時間:周一至周五9:00-18:00
          微信關注
          免費技術研討會
          獲取一手干貨分享

          互聯網違法不良信息舉報

          Reporting Internet Illegal and Bad Information
          editor@netbroad.com
          400-003-2006
          哥哥撸