回调用于层间协作,例如作为一个驱动,是一个底层,他在收到一个数据时,除了完成本层的处理工作外,还将进行回调,将这个数据交给上层应用层来做进一步处理,这在分层的数据通信中很普遍。
其实回调和API非常接近,他们的共性都是跨层调用的函数。但区别是API是低层提供给高层的调用,一般这个函数对高层都是已知的;而回调正好相反,他是高层提供给底层的调用,对于低层他是未知的,必须由高层进行安装,这个安装函数其实就是一个低层提供的API,安装后低层不知道这个回调的名字,但它通过一个函数指针来保存这个回调,在需要调用时,只需引用这个函数指针和相关的参数指针。
其实:回调就是该函数写在高层,低层通过一个函数指针保存这个函数,在某个事件的触发下,低层通过该函数指针调用高层那个函数。
我们举一个简单的例子吧,假设提供一个函数叫 EnumFont ,该函数是得到所有的字体,假设它的实现是
EnumFont()
{
while ( (f = FindNextFont()) !=NULL)
{
printf("fontname: " + f.name);
}
}
这样就循环显示出所有的字体名称。但是,开发者可能对字体信息另有用处,那么如何才能让开发者能使用这些信息呢,于是做改进:
EnumFont( void* userFunc )
{
while ( (f = FindNextFont()) !=NULL)
{
printf("fontname: " + f.name);
if ( userFunc!=NULL ) userFunc( f) ;
}
}
假设userFunc是一个函数void myfunc( FontObject font )这样使用者只需要定义一个函数:
void myfunc( FontObject font )
{
listCtrl.Addstring( font.name );
}
通过使用 EnumFont( myfunc ) 就可以将所有额字体信息添加到一个列表框中。那么我们称myfunc是一个回调函数,即让某个系统函数调用的函数。因此可以得出结论: 1.回调函数是由开发者按照一定的原型进行定义的函数。 2.回调函数并不由开发者直接调用执行。 3.回调函数通常作为参数传递给系统API,由该API来调用。 4.回调函数可能被系统API调用一次,也可能被循环调用多次。
比如函数
int EnumFontFamilies(HDC hdc, // handle to device control
LPCTSTR lpszFamily, // pointer to family-name string
FONTENUMPROC lpEnumFontFamProc, // pointer to callback function
LPARAM lParam // pointer to application-supplied data );
其中的FONTENUMPROC lpEnumFontFamProc就是一个回调函数,该函数遵照格式int CALLBACK EnumFontFamProc( ENUMLOGFONT FAR *lpelf, NEWTEXTMETRIC FAR *lpntm, int FontType, LPARAM lParam )进行定义。
我们看一下另外一个例子
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;
}