为什么要使用回调函数 ?
因为可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。
想知道回调函数在实际中有什么作用?先假设有这样一种情况:我们要编写一个库,它提供了某些排序算法的实现(如冒泡排序、快速排序、shell排序、shake排序等等),为了能让库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,能让库可用于多种数据类型(int、float、string),此时,该怎么办呢?可以使用函数指针,并进行回调。
一、一个最简单的例子:
程序代码:
#include <stdio.h>
#include <stdlib.h>
typedef int (*CalcFunc)(int, int); //this is function pointer
// function of Add
int add(int a, int b)
{
return a + b;
}
// function of Sub
int sub(int a, int b)
{
return a - b;
}
// now we callback the function by paramter "CalcFunc cf"
void call_back(CalcFunc cf, int a, int b)
{
printf("%d\n", cf(a, b));
}
int main()
{
call_back(add, 5, 3); // print result = 5 + 3;
call_back(sub, 5, 3); // print result = 5 - 3;
return 0;
}
二、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;
}
回调的另一个名称也叫闭包, 可以将接口与实现进行分离,例如第一个例子中的add和sub就是两个不同的实现,
在call_back函数不需要去关心这两个具体实现,而回调函数在这里正是扮演着接口的角色。当然,你也可以实现
mul乘法,div除法运算,这样可以让你体会到一个接口多个实现的味道,简称多态。