C/C++回调函数简要介绍
摘自:http://my.oschina.net/jungleliu0923/blog/198151?from=20140216
1、引子
在C/C++里面有个非常给力的库函数qsort,相信大家都用过。他的函数原型如下:
void qsort(void *base,size_tnmemb,size_tsize, int(*compar)(constvoid*, constvoid*));
使用的时候需要传递需要排序的数组base, 数组数目nmeb, 每个数组大小size,以及我们比较自定义的回调函数:compar.
2、概念
如compar所示,如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
和回调函数相对,普通函数调用一般为同步调用,即A模块阻塞调用B模块函数,B模块执行完毕之后会讲结果返回给A模块。
回调函数则不同。A模块定义一个回调函数C,将函数指针C传给B模块作为参数。在调用B模块之后,B模块会根据一定的条件触发回调C,进而重新调用模块A的函数。
这样模块B就不用关心回调函数自己的具体实现,这样可以是系统架构更加清晰,可以提高系统的可扩展性。
3、举例
现在我们有个模块叫callback模块。callback模块会接受主函数main传来的a,b,回调函数c.
如果a==100,那么就返回10000,否则就使用我们的回调函数,执行c(a,b),并返回。
具体如下所示:
3.1、通用头文件 pub.h
这里主要定义了一个函数指针。
函数原型为 int myfoo(int, int);
如果有疑问,请自行Google or Baidu.
01 | /*************************************************************************** |
02 | * |
03 | * Copyright (c) 2014 liujun&&baidu. inc All Rights Reserved |
04 | * |
05 | **************************************************************************/ |
06 |
07 | /* |
08 | * @filename: pub.h |
09 | * @version: 1.0 |
10 | * @date : 2014/01/28 14时44分05秒 |
11 | * @author: liujun (liujun0923@zju.edu.cn) |
12 | * @breif: |
13 | */ |
14 |
15 | #ifndef PUB_INC |
16 | #define PUB_INC |
17 |
18 | #include<stdio.h> |
19 |
20 | //定义一个回调函数,返回为int, 参数为int,int |
21 | typedef int (*myfoo)( int , int ); |
22 |
23 | #endif /* ----- #ifndef PUB_INC ----- */ |
3.2、callback模块
头文件callback.h: 主要定义了一个结构体,包括a,b,回调函数foo。同时有一个执行函数process.
01 | /*************************************************************************** |
02 | * |
03 | * Copyright (c) 2014 liujun&&baidu. inc All Rights Reserved |
04 | * |
05 | **************************************************************************/ |
06 |
07 | /* |
08 | * @filename: callback.h |
09 | * @version: 1.0 |
10 | * @date : 2014/01/28 14时46分31秒 |
11 | * @author: liujun (liujun0923@zju.edu.cn) |
12 | * @breif: |
13 | */ |
14 |
15 |
16 | #ifndef CALLBACK_INC |
17 | #define CALLBACK_INC |
18 |
19 | #include "pub.h" |
20 |
21 | typedef struct _foo_struct_t{ |
22 | int a; |
23 | int b; |
24 | myfoo foo; |
25 | }foo_struct_t; |
26 |
27 | int process(foo_struct_t* data); |
28 |
29 | #endif /* ----- #ifndef CALLBACK_INC ----- */ |
执行函数callback.c: 如果a=100,那么返回10000,否则使用回调函数来执行
01 | /*************************************************************************** |
02 | * |
03 | * Copyright (c) 2014 liujun&&baidu. inc All Rights Reserved |
04 | * |
05 | **************************************************************************/ |
06 |
07 | /* |
08 | * @filename: callback.c |
09 | * @version: 1.0 |
10 | * @date : 2014/01/28 14时48分26秒 |
11 | * @author: liujun (liujun0923@zju.edu.cn) |
12 | * @breif: |
13 | */ |
14 |
15 | #include "callback.h" |
16 |
17 | int process(foo_struct_t* data) |
18 | { |
19 | int res; |
20 | //这里你可以做很多事情。 |
21 |
22 | //这里你可以用主函数传来的函数指针来进行回调 |
23 | if ( data->a == 100) |
24 | { |
25 | res = 10000; |
26 | } |
27 | else |
28 | { |
29 | res = data->foo(data->a, data->b); |
30 | } |
31 | //你还是可以做很多事情 |
32 | return res; |
33 | } |
3.3、main模块
main.c: 从命令行接受参数a,b, 然后将a,b以及myfun函数地址一起参入模块callback。
01 | /*************************************************************************** |
02 | * |
03 | * Copyright (c) 2014 liujun&&baidu. inc All Rights Reserved |
04 | * |
05 | **************************************************************************/ |
06 |
07 | /* |
08 | * @filename: main.c |
09 | * @version: 1.0 |
10 | * @date : 2014/01/28 14时52分48秒 |
11 | * @author: liujun (liujun0923@zju.edu.cn) |
12 | * @breif: |
13 | */ |
14 |
15 | #include "pub.h" |
16 | #include "callback.h" |
17 | #include <stdlib.h> |
18 |
19 | int myfun( int a, int b) |
20 | { |
21 | return a+b; |
22 | } |
23 |
24 | int main( int argc, char ** argv) |
25 | { |
26 | foo_struct_t* data = (foo_struct_t*) malloc ( sizeof (foo_struct_t)); |
27 | data->a = atoi (argv[1]); |
28 | data->b = atoi (argv[2]); |
29 | data->foo = myfun; |
30 | int res = process(data); |
31 | printf ( "after callback is %d\n" , res); |
32 | free (data); |
33 | return 0; |
34 | } |
3.4、Makefile
先生存libcallback,然后生成可执行文件。
main: main.c libcallback
gcc -g main.c -I. -L. -lcallback -o main
libcallback:callback.h callback.c pub.h
gcc -g -c callback.h callback.c pub.h
ar -r libcallback.a callback.o
clean:
rm *.gch
rm *.o
rm *.a
rm main
3.5、执行结果
liujun@ubuntu:~/test/callback$ ./main 100 200
after callback is 10000
liujun@ubuntu:~/test/callback$ ./main 50 200
after callback is 250
可以看到达到我们预期效果。
最后给个具体的例子:
https://github.com/jungleliu0923/myserver
客户端C连接例子部分代码如下,其中mys_server_set_callback就是使用回调。
01 | int main() |
02 | { |
03 | my_log_init( "./log" , "sample.log" , "sample.log.wf" , 16); |
04 | server = my_server_create( "./conf/" , "myserver.conf" , "sample" ); |
05 | if (server == NULL) |
06 | { |
07 | cout << "create sever fail\n" ; |
08 | return -1; |
09 | } |
10 | my_server_set_callback(server, my_callback); |
11 | my_server_run(server); |
12 | return 0; |
13 | } |