1,什么是回调函数?
回调函数实质上是对函数指针的实践应用。
函数指针:
函数指针是一个变量,它存储了一个函数的地址。当将函数指针作为参数传递给另一个函数时,另一个函数就可以使用这个指针来调用该函数。
定义:
int (*method_call_type)(int a,int b);类型 (*函数名)(参数列表);
最基本使用方法:
#include <stdio.h>
int (*method_call_type)(int a,int b);//定义函数指针int add(int a,int b)
{printf("add\n");return a+b;
}void main()
{printf("正常调用 add 结果 = %d \n",add(3,4));//正常调用method_call_type=add;printf("函数指针调用 method_call_type(add) 结果 = %d \n",method_call_type(3,4));//函数指针调用;
}
执行结果:
[root@localhost ~]# gcc functest.c
[root@localhost ~]# ./a.out
add
正常调用 add 结果 = 7
add
函数指针调用 method_call_type(add) 结果 = 7
[root@localhost ~]#
2,我对回调函数应用的理解:
1,便于大型软件架构模块之间的解耦,也就是代码实现低耦合的一个方式。
2,便于大型软件架构模块划分,能使模块功能更加清晰。
大型软件框架一般都是分多模块分别编译,假设模块A对外提供函数接口,其他模块使用A的接口时需要使用A定义的结构体构造参数,如果接口改变或者参数结构体变化时。A模块代码更新了相关内容,其他模块使用A接口的地方没有改变,如果没有定义好那么会出现编译问题。但是如果做一个回调模块,A把接口功能都注册到回调模块(必须是公共模块),其他模块只需要引用回调模块的头文件和路径就行。这个时候A变更接口时只需要变更回调模块实现就行,其他模块就算不更新回调相关内容也不会出现编译问题。这个其实就是使用回调模块对其他模块做了个适配层,其他模块编译时不需要关心别的模块的影响(大不了就是某个模块的回调功能不可用)。
3,回调回调,就是来回调用的意思。回调函数可以提供一个函数集合,用户可以在程序运行的同一个点通过不同的需求来调用相同的回调函数来提供不同的函数方法。
我的理解,回调函数的使用一般在程序执行过程中的某个点,这个点有些特殊要求,比如一个数学运算集合(加减乘除),a同学执行到这个点需要做加法,b同学走到这个点需要做减法。因为这个点可能时a来,也可能时b来,对这个点执行的动作有不同的要求。那么这个时候就需要回调函数来处理。
实践1,简单的回调
定义一组数学方法,根据方法不同调用不同的数学实现。
举个例子:
main函数可以改成一般的函数,然后放到模块的需要的地方,就可以实现上面说的:不同条件运行到这个点可以提供不同的方法。
#include <stdio.h>
#include <stdlib.h>int add(int a,int b)
{printf("add\n");return a+b;
}int minus(int a,int b)
{printf("minus\n");return a-b;
}int multi(int a,int b)
{printf("multi\n");return a*b;
}int divid(int a,int b)
{printf("divid\n");return a/b;
}
/*回调过程定义----------start----------------------------------------------*/
enum
{E_ADD_METHOD,E_MIN_METHOD,E_MUL_METHOD,E_DIV_METHOD,E_MAX
};typedef int (*method_call_type)(int a,int b); //定义回调函数指针typedef struct
{method_call_type do_func;
}CALLBACK_TABLE_ST;CALLBACK_TABLE_ST g_methmatics_call_table[E_MAX] =
{[E_ADD_METHOD] = {.do_func = add},[E_MIN_METHOD] = {.do_func = minus},[E_MUL_METHOD] = {.do_func = multi},[E_DIV_METHOD] = {.do_func = divid},
};int methodcall_execute(int method,int a,int b)
{if( method>E_MAX || method < 0){printf("method error!\n");return 1;}if(g_methmatics_call_table[method].do_func){g_methmatics_call_table[method].do_func(a,b);}
}
/*回调过程定义----------end----------------------------------------------*/
void main(int argc, char* argv[])
{int a,b,c=0;int method = 0;if(argc<4){printf("need two argvs!\n");return;}a= atoi(argv[1]);b= atoi(argv[2]);method= atoi(argv[3]);switch(method){case E_ADD_METHOD:printf(" method add [%d+%d=%d]\n",a,b,add(a,b));break;case E_MIN_METHOD:printf(" method minus [%d-%d=%d]\n",a,b,minus(a,b));break;case E_MUL_METHOD:printf(" method multi [%d*%d=%d]\n",a,b,multi(a,b));break;case E_DIV_METHOD:printf(" method divid [%d/%d=%d]\n",a,b,divid(a,b));break;default:break;}printf("-------callbacktest!------\n");printf("result %d\n",methodcall_execute(method,a,b));return;
}
运行结果:
[root@localhost callbacktest]# ./test 8 2
need two argvs!
Segmentation fault
[root@localhost callbacktest]# ./test 8 2 1
minusmethod minus [8-2=6]
-------callbacktest!------
minus
result 6
[root@localhost callbacktest]# ./test 8 2 2
multimethod multi [8*2=16]
-------callbacktest!------
multi
result 16
[root@localhost callbacktest]# ./test 8 2 3
dividmethod divid [8/2=4]
-------callbacktest!------
divid
result 4
[root@localhost callbacktest]# ./test 8 2 4
-------callbacktest!------
result 0
[root@localhost callbacktest]# ./test 8 2 0
addmethod add [8+2=10]
-------callbacktest!------
add
result 10