Cのコールバック関数

21546 ワード

ソフトウェアモジュールの間には常に一定のインタフェースが存在し、呼び出し方式から、同期呼び出し、コールバック、非同期呼び出しの3種類に分けることができます.同期呼び出しはブロック呼び出しであり、呼び出し側は相手の実行が完了するまで待たなければならない.これは一方向呼び出しである.コールバックは双方向呼び出しモードであり、すなわち、呼び出された側もインタフェースが呼び出されたときに相手のインタフェースを呼び出す.非同期呼び出しは、メッセージまたはイベントのようなメカニズムですが、その呼び出し方向は正反対であり、インタフェースのサービスは、メッセージを受信したり、イベントが発生したりしたときに、クライアント(すなわち、クライアントを呼び出すインタフェース)に自発的に通知します.コールバックと非同期呼び出しの関係は非常に緊密であり、通常、コールバックを使用して非同期メッセージの登録を実現し、異なるステップでメッセージの通知を実現します.同期呼び出しは3つの中で最も簡単であり、コールバックは常に非同期呼び出しの基礎である.
コールバック関数とは?
簡単に言えば、コールバック関数は、関数ポインタによって呼び出される関数です.関数のポインタ(アドレス)をパラメータとして別の関数に渡すと、このポインタが指向する関数を呼び出すために使用されると、コールバック関数と言います.コールバック関数は、その関数の実装者によって直接呼び出されるのではなく、特定のイベントまたは条件が発生したときに他の側によって呼び出され、そのイベントまたは条件に応答するために使用される.
関数ポインタについては、以下を参照してください.http://www.cnblogs.com/kunhu/p/3700610.html  
コールバック関数を使用する理由
呼び出し者と被呼び出し者を分けることができるからです.呼び出し者は、呼び出し者が誰であるかに関心を持たず、特定のプロトタイプ、戻り値intなどの制限条件を持つ呼び出された関数があるだけであることを知る必要があります.
コールバックはC言語では関数ポインタによって実現され,コールバック関数のアドレスを被調関数に渡すことによってコールバックが実現される.したがって、コールバックを実行するには、まず関数ポインタを定義する必要があります.
1 void Func(char *s);//     
2 void (*pFunc) (char *);//    

 



コールバック関数は、通常の関数のようにプログラムによって呼び出されてもよいが、それがパラメータとしてコールバック関数に渡される場合にのみコールバック関数と呼ばれる.
変調関数の例:
 1 void GetCallBack(pcb callback)
 2 {
 3 /*do something*/
 4 }
 5            ,        pcb       :
 6 void fCallback(char *s) 
 7 {
 8 /* do something */
 9 } 
10   ,      fCallback         GetCallBack,
11 GetCallBack(fCallback);

 


, 。 , 。


コールバック関数は明示的に呼び出せない関数です.呼び出しは、コールバック関数のアドレスを呼び出し元に渡すことによって実現される.コールバック関数の使用は必要であり,統一インタフェースを介して異なる内容を実現したい場合には,コールバック関数を用いるのが適切である.例えば、いくつかの異なるデバイスに対してそれぞれ異なる表示関数を書きました:void TVshow();void ComputerShow(); void NoteBookShow()...などなど.これは私たちが統一的な表示関数を使いたいので、私たちはこの時関数を戻すことができます.
    void show(void (*ptr)());
使用時に、入力されたパラメータに応じて異なるコールバック関数が呼び出されます.
異なるプログラミング言語には異なる構文がある可能性があります.次に、1つのc言語におけるコールバック関数の例を挙げます.1つのコールバック関数はパラメータを持たず、もう1つのコールバック関数はパラメータを持っています.
例1:
 
//Test.c
 
 
 1 #include <stdlib.h>
 2 
 3 #include <stdio.h>
 4 
 5  
 6 
 7 int Test1()
 8 
 9 {
10 
11    int i;
12 
13    for (i=0; i<30; i++)
14 
15    {
16 
17      printf("The %d th charactor is: %c/n", i, (char)('a' + i%26));
18 
19     }
20 
21    return 0;
22 
23 }
24 
25 int Test2(int num)
26 
27 {
28 
29    int i;
30 
31    for (i=0; i<num; i++)
32 
33    {
34 
35     printf("The %d th charactor is: %c/n", i, (char)('a' + i%26));
36 
37     }
38 
39    return 0;
40 
41 }
42 
43  
44 
45 void Caller1(void (*ptr)())//            
46 
47 {
48 
49    (*ptr)();
50 
51 }
52 
53 void Caller2(int n, int (*ptr)())//            ,                   ,
54 
55 { //    void Caller2(int (*ptr)(int n)),         。
56 
57    (*ptr)(n);
58 
59    return;
60 
61 }
62 
63 int main()
64 
65 {
66 
67    printf("************************/n");
68 
69    Caller1(Test1); //     Test2();
70 
71    printf("&&&&&&************************/n");
72 
73    Caller2(30, Test2); //     Test2(30);
74 
75    return 0;
76 
77 }

 
 
 
 
以上、コールバック関数のアドレスをコールバック者に渡すことによって呼び出しが実現されたが、参照付きコールバック関数の使い方に注意が必要である.コールバックを実現するには、まず関数ポインタを定義する必要があります.関数ポインタの定義はここで少しお話しします.例えば、int(*ptr)();ここでptrは関数ポインタであり、(*ptr)のカッコは省略できません.カッコの優先度が星より高いため、戻りタイプが整数の関数宣言になります.
 
C言語の標準ライブラリ関数では,コールバック関数を用いてユーザに処理プロセスをカスタマイズさせることが多い.一般的なクイックソート関数、二分検索関数などです.
クイックソート関数のプロトタイプ:
 
  
1 void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const void *));
3 4 void *bsearch(const void *key, const void *base, size_t nelem,size_t width, int (_USERENTRY *fcmp)(const void *, const void *));
 
  

 

 

fcmpはコールバック関数の変数です.
具体的なC例を以下に示す.
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 int sort_function( const void *a, const void *b);
 4 int list[5] = { 54, 21, 11, 67, 22 };
 5 int main(void)
 6 {
 7    int  x;
 8    qsort((void *)list, 5, sizeof(list[0]), sort_function);
 9    for (x = 0; x < 5; x++)
10       printf("%i
", list[x]); 11 return 0; 12 } 13 int sort_function( const void *a, const void *b) 14 { 15 return *(int*)a-*(int*)b; 16 }

 


c++

   
 1 class CTest;
 2 typedef void (CTest::*DoMessageFunc)(char* msg, int msgid );
 3 class CTest
 4 {
 5 public:
 6     CTest(){}
 7     ~CTest(){}
 8     void DoMsgFunc1(char* pMsg,int nID)
 9     {
10         printf("%s
",pMsg); 11 printf("
"); 12 } 13 void RegiestMsg(int nSrcID,DoMessageFunc pFunc) 14 { 15 m_pFunc = pFunc; 16 } 17 void HandleMessage(int nMsgID, char* pMsg, int nID) 18 { 19 (this->*m_pFunc)(pMsg,nID); 20 } 21 private: 22 DoMessageFunc m_pFunc; 23 }; 24 using namespace std; 25 int main(int argc, char* argv[]) 26 { 27 printf("Starting......
"); 28 CTest obj ; 29 obj.RegiestMsg(12,&CTest::DoMsgFunc1); 30 obj.HandleMessage(1,"test",6); 31 printf("Ending......
"); 32 return 0; 33 }

 


http://xenyinzen.wikidot.com/reship:080123-8
http://www.ibm.com/developerworks/cn/linux/l-callback/
http://blog.csdn.net/woyaowenzi/article/details/3950116
http://blog.chinaunix.net/uid-22488454-id-3057473.html