当前位置:编程学习 > C/C++ >>

关于回调函数

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
 
补充:软件开发 , C语言 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,