zoukankan      html  css  js  c++  java
  • 回调函数

      回调函数:顾名思意,就是使用者自己定义一个函数,使用者自己定义这个函数的功能,然后把 这个函数作为参数 传入到 其他函数 中,由  其他函数 在运行时来调用的函数。该“其他函数”就是回调函数(特点:它 主动调用 别的函数)

      什么是回调函数呢?回调函数其实就是一个通过函数指针调用的函 数!假如你把A函数的指针当作参数传给B函数,然后在B函数中通过A函数传进来的这个指针调用A函数,那么这就是回调机制。B函数就是回调函数,而通常情 况下,A函数是系统在符合你设定条件的情况下会自动执行,比如Windows下的消息触发等等。那么调用者和被调用者的关系就被拉开了,就像是中断处理函 数那样。

       简单的说:由 其他的函数 运行期间来回调 你定义的函数;(这两个函数 被捆绑在一起 运行)

     1 //不带参数版
     2 #include <stdio.h>
     3 
     4 void func()    //定义回调函数的调用函数;
     5 {
     6     printf("hello world !! 
    ");
     7 }
     8 
     9 void mycall_back(void(*call_back_test)()) //实现回调函数
    10 {
    11     call_back_test();
    12 }
    13 
    14 int main()
    15 {
    16     mycall_back(func);
    17     return 0;
    18 }
    //回调函数带参数版
    1
    #include <stdio.h> 2 3 void func(int t) 4 { 5 printf("hello world !! %d ", ++t); 6 } 7 //void mycall_back((*call_back_test) (int), int k) //error; 8 void mycall_back(void (*call_back_test) (int), int k)   //注意参数写法 9 { 10 call_back_test(k); 11 } 12 13 int main() 14 { 15 mycall_back(func, 8);  //注意参数写法; 16 return 0; 17 }

    下面给出回调函数的标准定义:

      简而言之,回调函数就是一个 通过函数指针调用的 函数。如果把 函数的指针(地址)作为参数传递给另一个函数, 当这个指针 被作 调用它指向的函数时,我们就说 这个函数是回调函数;

      为什么要使用回调函数?

      因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为int)的被调用函数。

       如果想知道回调函数在实际中有什么作用,先假设有这样一种情况,我们要编写一个库,它提供了某些排序算法的实现,如冒泡排序、快速排序、shell排 序、shake排序等等,但为使库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,想让库可用于多种数据类型(int、 float、string),此时,该怎么办呢?可以使用函数指针,并进行回调。

      回调可用于通知机制,例如,有时要在程序中设置一个 计时器,每到一定时间,程序会得到相应的通知,但通知机制的实现者对我们的程序一无所知。而此时,就需有一个特定原型的函数指针,用这个指针来进行回调, 来通知我们的程序事件已经发生。实际上,SetTimer() API使用了一个回调函数来通知计时器,而且,万一没有提供回调函数,它还会把一个消息发往程序的消息队列。

      另一个使用回调机制的 API函数是EnumWindow(),它枚举屏幕上所有的顶层窗口,为每个窗口调用一个程序提供的函数,并传递窗口的处理程序。如果被调用者返回一个 值,就继续进行迭代,否则,退出。EnumWindow()并不关心被调用者在何处,也不关心被调用者用它传递的处理程序做了什么,它只关心返回值,因为 基于返回值,它将继续执行或退出。

    示例一个:

     1 #include <stdio.h>
     2 
     3 typedef void (*callback_t)(void *);
     4 
     5 void repeat_three_times(callback_t f, void *para)
     6 {
     7     f(para);
     8 }
     9 
    10 void say_hello(void *str)
    11 {
    12     printf("Hello %s
    ", (const char *)str);
    13 } 
    14 
    15 void count_numbers(void *num)
    16 {
    17     int i;
    18     for(i=1;i<=(int)num;i++)
    19         printf("%d ", i);
    20     putchar('
    ');
    21 }
    22 
    23 int main()
    24 {
    25      repeat_three_times(say_hello, "Guys");
    26      repeat_three_times(count_numbers,  (void *)4);
    27      return 0;
    28 }

     示例二

     1 #include <stdio.h>
     2 typedef int (cmp_t)(void *a, void *b);
     3 
     4 typedef struct
     5 {
     6     const char *name;
     7     int score;
     8 }student_t;
     9 
    10 int cmp_student(void *a, void *b) 
    11 {
    12     if(((student_t *)a)->score > ((student_t *)b)->score)
    13         return 1;
    14     if(((student_t*)a)->score == ((student_t *)b)->score)
    15         return 0;
    16     else
    17         return -1; 
    18 
    19     return 0;
    20 }
    21 
    22 void *max(void *data[], int num, cmp_t cmp)
    23 {
    24     int i;
    25     void *tmp = data[0];
    26     for(i=1; i<num; i++)
    27     {   
    28         if(cmp(tmp, data[i]) < 0)
    29             tmp = data[i];
    30     }   
    31     return tmp;
    32 }
    33 
    34 int main()
    35 {
    36     student_t list[4] = {{"Tom", 68}, {"Jerry", 72}, {"John", "87"}, {"Chris", 99}};
    37     student_t *plist[4] = {&list[0], &list[1], &list[2], &list[3]};
    38     student_t *pmax = max((void**)plist, 4, cmp_student);
    39     printf("%s gets the highest score %d
    ", pmax->name, pmax->score);
    40 
    41     return 0;
    42 }

      max函数之所以能对一组任意类型的对象进行操作,关键在于传给max的是指向对象的指针所构成的数组,而不是对象本身所构成的数组,这样max不必关心对象到底是什么类型,只需要转给比较函数cmp,然后根据比较结果做对应操作即可,cmp是调用者提供的回调函数,调用者就知道对象是什么类型以及如何比较;

    以上举例的回调函数是被同步调用的,调用者调用max函数,max函数则调用cmp函数,相当于调用者间接调了自己提供的回调函数。在实际系统中,异步调用也是回调函数的一种典型用法,调用者首先将回调函数传给实现者,实现者记住这个函数,这称为注册一个回调函数,然后当某个事件发生时实现者再调用先前注册的函数,比如sigaction(2)注册一个信号处理函数,当信号产生时由系统调用该函数进行处理,再比如pthread_create(3)注册一个线程函数,当发生调度时系统切换到新注册的线程函数中运行,在GUI编程中异步回调函数更是有普遍的应用,例如为某个按钮注册一个回调函数,当用户点击按钮时调用它。

  • 相关阅读:
    CF763C Timofey and Remoduling
    CF762E Radio Stations
    CF762D Maximum Path
    CF763B Timofey and Rectangles
    URAL1696 Salary for Robots
    uva10884 Persephone
    LA4273 Post Offices
    SCU3037 Painting the Balls
    poj3375 Network Connection
    Golang zip压缩文件读写操作
  • 原文地址:https://www.cnblogs.com/chris-cp/p/3492423.html
Copyright © 2011-2022 走看看