欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

关于回调函数

程序员文章站 2023-08-24 16:45:08
1.什么是回调函数。  在freerdp的项目中看到,几乎所有的绘制工作都是通过回调函数完成的。究竟什么是回调函数呢?要了解回调函数,还得中函数指针说起。那函数指针又是...

1.什么是回调函数。
 在freerdp的项目中看到,几乎所有的绘制工作都是通过回调函数完成的。究竟什么是回调函数呢?要了解回调函数,还得中函数指针说起。那函数指针又是什么呢?它跟指针函数有什么关系呢?请看下面:
一般我们是这样声明一个函数的,
int func(int params, ...);
相信大家对函数最熟悉不过了,这是个返回值为int的函数。稍微变形一下就成了指针函数了,请看:
int* func(int params, ...);
一个函数不仅可以带回一个整型数据的值,字符类型值和实型类型的值,还可以带回指针类型的数据,使其指向某个地址单元。当一个函数的返回值是一个指针时,该函数就是一个指针函数。那跟指针函数有什么关系呢?先看看指针函数的定义吧。
 
 
在程序运行中,函数代码是程序的算法指令部分,它们和数组一样也占用存储空间,都有相应的地址。可以使用指针变量指向数组的首地址,也可以使用指针变量指向函数代码的首地址,指向函数代码首地址的指针变量称为函数指针。
int func(int x); /* 声明一个函数 */
  int (*f) (int x); /* 声明一个函数指针 */
  f=func; /* 将func函数的首地址赋给指针f */
 
 
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。
2.为什么要使用回调函数
 
  因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为int)的被调用函数。
  如果想知道回调函数在实际中有什么作用,先假设有这样一种情况,我们要编写一个库,它提供了某些排序算法的实现,如冒泡排序、快速排序、shell排序、shake排序等等,但为使库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,想让库可用于多种数据类型(int、float、string),此时,该怎么办呢?可以使用函数指针,并进行回调。
  回调可用于通知机制,例如,有时要在程序中设置一个计时器,每到一定时间,程序会得到相应的通知,但通知机制的实现者对我们的程序一无所知。而此时,就需有一个特定原型的函数指针,用这个指针来进行回调,来通知我们的程序事件已经发生。实际上,settimer() api使用了一个回调函数来通知计时器,而且,万一没有提供回调函数,它还会把一个消息发往程序的消息队列。
  不管怎么说,回调函数是继续自c语言的,因而,在c++中,应只在与c代码建立接口,或与已有的回调接口打交道时,才使用回调函数。除了上述情况,在c++中应使用虚拟方法或函数符(functor),而不是回调函数。
 3.回调函数的实现
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
 #include <math.h>
 #include <malloc.h>
 /*
file: darray.c:回调函数冒泡排序函数实现
author: ecorefeng
created on 2010年8月
*/
 /*
 *定义一个用于自动测试的宏(关于自动测试请我的博客文章《自动测试的优劣》)
 */
 #define return_val_if_fail(p, val)\
 if(!(p)){printf("%s:%d"#p" failed", func, line); return val; }
 

/*
 *定义一个回调函数原型,用于回调
 */
typedef int (*compfunc)(void *ctx, void *data);
/*
 *功能:实现冒泡排序
 *参数:array:要排序的数组 compfunc:回调的用于比较的函数 array_len:数组长度
 *返回:
 */
int darray_b_sort(void **array,compfunc compfunc, int array_len)
 {
 return_val_if_fail(array !=null&&compfunc !=null, 1);
int len = 0;
 int max = 0;
 int index = 0;
for(len = array_len - 1; len > 0; len--)
 {
 for(index = 1, max = 0; index < len; index++)
 {
 if(compfunc(array[index], array[max]) > 0)
 {
 max = index;
 }
}
 if(compfunc(array[max], array[len]) > 0)
 {
 void *data = array[max];
 array[max] = array[len];
 array[len] = data;
 }
//int i = 0;
 //for(i = 0; i < 6; i++)
 //{
 //printf("%d\n",array[i]);
 // assert(array[i] >= array[i-1]);
 //}
 //printf(".......................\n");
}
return 0;
 }
 /*
 *功能:随机生成一个数组
 *参数:num:数组长度
 *返回:数组指针
 */
static void **int_array_create(int num)
 {
 int i = 0;
 int *array = (int *)malloc(sizeof(int) * num);
for(i = 0; i < num; i++)
 {
 array[i] = rand()%100;
 printf("%d\t",array[i]);
}
 printf("***********************\n");
 return(void **)array;
}
 /*
 *功能:实现比较
 *参数:compfunc:回调的用于比较的函数 num:数组长度
 *返回:数组指针
 */
 static void sort_test_asc_or_desc(compfunc compfunc, int num)
 {
 void **array = int_array_create(num);
 darray_b_sort(array, compfunc, num);
int i = 0;
 for(i = 0; i < num; i++)
 {
 printf("%d\t",(int)array[i]);
 // assert(array[i] >= array[i-1]);
 }
free(array);
 }
 /*
 *功能:实现比较函数(升序)
 *参数:指针
 *返回:比较结果:大于0、小于0;
 */
 int int_sort_compfunc_asc(void *num1, void *num2)
 {
 return (int)num1 - (int)num2;
 }
 /*
 *功能:实现比较函数(降序)
 *参数:指针
 *返回:比较结果:大于0、小于0;
 */
 int int_sort_compfunc_desc(void *num1, void *num2)
 {
 return (int)num2 - (int)num1;
 }
int main(int argc, char *argv[])
 {
 sort_test_asc_or_desc(int_sort_compfunc_asc, 20);
 printf("................\n");
 sort_test_asc_or_desc(int_sort_compfunc_desc, 10);
return 0;
 }


 回调函数的形式实现的升降序的冒泡排序算法例子。
感谢ecorefeng提供的程序例子。
回头看看freerdp的项目,正是由于回调函数的使用,使得freerdp的移植变得简单多了。例如我是用skia库实现rdp的绘制函数时,不需要了解整个的调用过程,我只需要实现回调函数调用的那些函数,然后注册这些回调函数就可以了。
由于知识有限,难免有错,欢迎大家指正,谢谢。

 

摘自 hopetribe