深入淺出剖析C語言函數指標與回呼函數(一)【轉】

來源:互聯網
上載者:User

標籤:end   ace   sse   linux   c語言函數   stdio.h   函數指標   工作   打包   

本文轉載自:http://blog.csdn.net/morixinguan/article/details/65494239

關於靜態庫和動態庫的使用和製作方法。

http://blog.csdn.NET/morixinguan/article/details/52451612

今天我們要搞明白的一個概念叫回呼函數。

什麼是回呼函數?

百度的權威解釋如下:

回呼函數就是一個通過函數指標調用的函數。如果你把函數的指標(地址)作為參數傳遞給另一個函數,當這個指標被用來調用其所指向的函數時,我們就說這是回呼函數。回呼函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用於對該事件或條件進行響應

那麼我們可以來看一個例子:

 

[cpp] view plain copy  print?
  1. #include <stdio.h>  
  2. void print();  
  3. int main(void)  
  4. {  
  5.     void (*fuc)();   
  6.     fuc = print ;   
  7.     fuc();    
  8. }   
  9. void print()  
  10. {  
  11.     printf("hello world!\n");  
  12. }  

 

從這個例子可以看到,我們首先定義了一個函數指標fuc ,這個函數指標的傳回值為void型,然後我們給函數指標賦值,賦值為print,也就是print函數的首地址,此時fuc獲得了print的地址,fuc的地址等於print的地址,所以最終調用fuc();也就相當於調用了print();

那麼我寫的這個例子明顯和百度解釋的不符合啊?定義是如果你把函數的指標(地址)作為參數傳遞給另一個函數,當這個指標被用來調用其所指向的函數時,我們就說這是回呼函數,確實,有所不同,但道理是一樣的,我們接下來再來看一個例子。

 

[cpp] view plain copy  print?
  1. #include <stdio.h>  
  2.   
  3. int add_ret() ;  
  4.   
  5. int add(int a , int b , int (*add_value)())  
  6. {  
  7.     return (*add_value)(a,b);  
  8. }  
  9.   
  10. int main(void)  
  11. {  
  12.     int sum = add(3,4,add_ret);  
  13.     printf("sum:%d\n",sum);  
  14.     return 0 ;  
  15. }   
  16.   
  17. int add_ret(int a , int b)  
  18. {  
  19.     return a+b ;  
  20. }  

 

從這個例子裡,我們看到:

這樣子不就符合我們的定義了嘛?我們把函數的指標(地址),這裡也就是add_ret,作為參數int add(int a , int b , int (*add_value)()) , 這裡的參數就是int(*add_value)() , 這個名字可以隨便取,但是要符合C語言的命名規範。當這個指標被用來調用其所指向的函數時,我們就說這是回呼函數。我們看到add函數內部,return (*add_value)(a,b) ; 這個(*add_value)(a,b)相當於對指標進行了簡引用,我們在main函數中,傳入具體要實現功能的函數,add_ret,這個函數很簡單,就是實現兩數相加並返回,這裡剛剛好,簡引用,相當於取出指標返回地址裡的值,這個值就是return a+b,也就是我們傳入a和b兩數相加的結果。

         那麼,回呼函數究竟有什麼作用呢?

 

說到這裡,就有了使用者和開發人員之間的概念,比方說,剛剛說的add()這個函數,假設一下,使用者是實現add_value這個函數,而開發人員是實現add_value這個函數,使用者做的工作不多,就是想要通過開發人員實現的這麼一個介面,然後在函數中通過調用開發人員實現的這個介面的傳回值,然後來實現我們的功能。這個開發人員角色就很多了,可以是自己公司的核心開發人物,也可以是別的工作的外包商的人物,這時候,他作為一個開發人員的角色完完全全可以將add_value實現的add_ret這個函數封裝起來並且加密,然後扔一個.so或者.a給使用者,那麼使用者就看不到具體add_ret的實現內容,使用者只需要開發人員給他提供一個.h和.so即可,這樣,作為開發人員,他就將他實現的函數功能給保密了。

 

 接下來,我們用Linux來示範下這個結果:

         我們在目錄下建立三個檔案,main.c,vendor.c,vendor.h

         Main.c是使用者開發的

         Vendor.c和vendor.h是開發人員實現的。

在main.c中,代碼如下:

 

[cpp] view plain copy  print?
  1. #include <stdio.h>  
  2. #include "vendor.h"  
  3.   
  4. int add(int a , int b , int (*add_value)())  
  5. {  
  6.     return (*add_value)(a,b);  
  7. }  
  8.   
  9. int main(void)  
  10. {  
  11.     int sum = add(3,4,add_ret);  
  12.     printf("sum:%d\n",sum);  
  13.     return 0 ;  
  14. }   

vendor.c,代碼如下:

 

 

[cpp] view plain copy  print?
  1. #include "vendor.h"  
  2. int add_ret(int a , int b)  
  3. {  
  4.     return a+b ;  
  5. }  

vendor.h,代碼如下:

 

 

[cpp] view plain copy  print?
  1. #ifndef __VENDOR_H  
  2. #define __VENDOR_H  
  3.   
  4. int add_ret(int a, int b) ;  
  5.   
  6. #endif  

 

 

接下來,我們製作一個動態連結程式庫,最終開發人員把vendor.c的內容封起來,把vendor.h提供給使用者使用。

 

在linux下製作動態連結程式庫,將vendor.c和vendor.h打包成一個動態連結程式庫

先明白以下幾個命令是什麼意思:

產生動態庫:

gcc -shared -fPIC dvendor.c -o libvendor.so    

-shared : 產生動態庫;

-fPIC  : 產生與位置無關代碼;

-o               :指定產生的目標檔案;

 

使用動態庫:

gcc main.c -L . –lvendor -o main

-L : 指定庫的路徑(編譯時間); 不指定就使用預設路徑(/usr/lib/lib)

-lvendor : 指定需要動態連結的庫是誰;

代碼運行時需要載入動態庫:

./main 載入動態庫 (預設載入路徑:/usr/lib /lib ./ ...)

./main

我們將編譯動態庫產生的libvendor.so拷貝到/usr/lib後,現在就不需要vendor.c了,此時我們將vendor.c移除,也可以正常的編譯並且執行main函數的結果,這就是回呼函數的作用之一。

深入淺出剖析C語言函數指標與回呼函數(一)【轉】

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.