定义:
被调者回头调用调用着的函数,这种由调用方自己提供的函数叫回调函数
应用场景举例:
现有一个快速排序算法,实现了快排算法的逻辑,但是快排算法中必须涉及数据大小的比较,为提高程序的通用性,掉用者提供一个比较函数,这样排序函数借此调用调用者的函数来比较大小。
应用详解:
回调在C语言中是通过函数指针来实现的,通过将回调函数的地址传给被掉函数从而实现回调。因此要实现回调,必须首先定义函数指针,如:
void Func(char *s);函数原型
void (*pFunc)(char *);//函数指针
可以看出,函数的定义和函数指针的定义非常类似,一般来说,为了简化函数指针类型变量定义,提高程序的可读性,我们需要把函数指针类型自定义一下。
typedef void(*pcb)(char *) pcb;
被调函数的例子:
void GetCallBack(pcb callBack)
{
/*do something*/
}
     用户在调用上面的函数时,需要自己实现一个pcb类型的回调函数:
   void fCallBack(char *s)
{
/*do something*/
}
然后,就可以直接把fCallBack当作一个变量传递给GetCallBack,
GetCallBack(fCallBack)
如果赋了不同的值给该参数,那么调用者将调用不同地址的函数。赋值可以发生在运行时,这样使你能实现动态绑定。
(2 )参数传递规则
到目前为止,我们只讨论了函数指针及回调而没有去注意ANSI C/C++的编译器规范。许多编译器有几种调用规范。如在Visual C++中,可以在函数类型前加_cdecl,_stdcall或者_pascal来表示其调用规范(默认为_cdecl)。C++ Builder也支持_fastcall调用规范。调用规范影响编译器产生的给定函数名,参数传递的顺序(从右到左或从左到右),堆栈清理责任(调用者或 者被调用者)以及参数传递机制(堆栈,CPU寄存器等)。
将调用规范看成是函数类型的一部分是很重要的;不能用不兼容的调用规范将地址赋值给函数指针。例如:
// 被调用函数是以int为参数,以int为返回值
__stdcall int callee(int);
// 调用函数以函数指针为参数
void caller( __cdecl int(*ptr)(int));
// 在p中企图存储被调用函数地址的非法操作
__cdecl int(*p)(int) = callee; // 出错
指针p和callee()的类型不兼容,因为它们有不同的调用规范。因此不能将被调用者的地址赋值给指针p,尽管两者有相同的返回值和参数列
(3 )应用举例
C语言的标准库函数中很多地方就采用了回调函数来让用户定制处理过程。如常用的快速排序函数、二分搜索函数等。
快速排序函数原型:
void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const void *));
二分搜索函数原型:
void *bsearch(const void *key, const void *base, size_t nelem, 
size_t width, int (_USERENTRY *fcmp)(const void *, const void *));
其中fcmp就是一个回调函数的变量。
下面给出一个具体的例子:
#include <stdio.h> 
#include <stdlib.h> 
int sort_function( const void *a, const void *b); 
int list[5] = { 54, 21, 11, 67, 22 }; 
int main(void) 
{ 
int x; 
qsort((void *)list, 5, sizeof(list[0]), sort_function); 
for (x = 0; x < 5; x++) 
printf("%i\n", list[x]); 
return 0; 
} 
int sort_function( const void *a, const void *b) 
{ 
return *(int*)a-*(int*)b; 
}
 
                     
                    
                 
                    
                 
 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号