1 简介 C语言最难的地方莫过于各种类型的指针,光听名字就把人给绕晕了。这里介绍一下指针函数和函数指针还有回调函数
2 指针函数 指针函数:指的是函数的返回值是一个指针,比如我的函数返回的是一个指向整数int的指针,定义格式如下:
简单的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 typedef struct _Data { int a; int b; }Data; Data* f (int a,int b) { Data * data = new Data; data->a = a; data->b = b; return data; } int main (int argc, char *argv[]) { QApplication a (argc, argv) ; Data * myData = f(4 ,5 ); qDebug() << "f(4,5) = " << myData->a << myData->b; return a.exec(); }
3 函数指针 函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。
1 2 int (*p)(int x, int y); int (*p)(int , int );
函数指针是需要把一个函数的地址赋值给它,有两种写法:
1 2 x = (*fun)(); x = fun();
简单的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int add (int x,int y) { return x+y; } int sub (int x,int y) { return x-y; } int (*fun)(int x,int y);int main (int argc, char *argv[]) { QApplication a (argc, argv) ; fun = add; qDebug() << "(*fun)(1,2) = " << (*fun)(1 ,2 ) ; fun = ⊂ qDebug() << "(*fun)(5,3) = " << (*fun)(5 ,3 ) << fun(5 ,3 ); return a.exec(); }
主要的用途包括:
回调函数: 函数指针常常用于实现回调机制,其中一个函数将另一个函数的地址传递给第三方函数,以便在适当的时候调用这个函数。这种机制常见于事件处理、图形界面编程和异步编程等场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 typedef void (*CallbackFunction) (int ) ;void process (int data, CallbackFunction callback) { callback(data); } void myCallback (int data) { printf ("Callback called with data: %d\n" , data); } int main () { process(42 , myCallback); return 0 ; }
动态选择函数: 函数指针可以在运行时动态选择要调用的函数。这对于实现多态性或根据条件选择不同的算法非常有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 c typedef int (*Operation) (int , int ) ;int add (int a, int b) { return a + b; } int subtract (int a, int b) { return a - b; } int performOperation (int a, int b, Operation op) { return op(a, b); } int main () { printf ("Result: %d\n" , performOperation(5 , 3 , add)); printf ("Result: %d\n" , performOperation(5 , 3 , subtract)); return 0 ; }
函数指针数组: 函数指针可以存储在数组中,用于根据索引或其他条件选择要调用的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 c typedef void (*CommandFunction) () ;void command1 () { printf ("Executing command 1\n" ); } void command2 () { printf ("Executing command 2\n" ); } int main () { CommandFunction commands[] = {command1, command2}; commands[0 ](); commands[1 ](); return 0 ; }
函数作为参数传递: 函数指针可以作为参数传递给其他函数,从而允许更灵活的函数组合和高阶函数的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 c typedef int (*MathFunction) (int , int ) ;int add (int a, int b) { return a + b; } int multiply (int a, int b) { return a * b; } int combine (MathFunction operation, int x, int y) { return operation(x, y); } int main () { printf ("Result: %d\n" , combine(add, 3 , 4 )); printf ("Result: %d\n" , combine(multiply, 3 , 4 )); return 0 ; }
4 回调函数 先来看看来自维基百科的对回调(Callback)的解析 :In computer programming, a callback is any executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at a given time. This execution may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback. 也就是说,把一段可执行的代码像参数传递那样传给其他代码,而这段代码会在某个时刻被调用执行,这就叫做回调。如果代码立即被执行就称为同步回调,如果在之后晚点的某个时间再执行,则称之为异步回调。
解释还是有点晕。。
4.1 为什么需要回调函数 我们先来了解一下回到函数的好处和作用,那就是解耦,对,就是这么简单的答案,就是因为这个特点,普通函数代替不了回调函数。所以,在我眼里,这才是回调函数最大的特点。来看看维基百科上面我觉得画得很好的一张图片。
下面以一段不完整的 C 语言代码来呈现上图的意思:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> #include <softwareLib.h> int Callback () { return 0 ; } int main () { Library(Callback); return 0 ; }
乍一看,回调似乎只是函数间的调用,和普通函数调用没啥区别,但仔细一看,可以发现两者之间的一个关键的不同:在回调中,主程序把回调函数像参数一样传入库函数。这样一来,只要我们改变传进库函数的参数,就可以实现不同的功能,这样有没有觉得很灵活?并且丝毫不需要修改库函数的实现,这就是解耦。再仔细看看,主函数和回调函数是在同一层的,而库函数在另外一层,想一想,如果库函数对我们不可见,我们修改不了库函数的实现,也就是说不能通过修改库函数让库函数调用普通函数那样实现,那我们就只能通过传入不同的回调函数了,这也就是在日常工作中常见的情况
4.2 同步回调和异步回调 同步回调:把函数b传递给函数a。执行a的时候,回调了b,a要一直等到b执行完才能继续执行;
异步回调:把函数b传递给函数a。执行a的时候,回调了b,然后a就继续往后执行,b独自执行。
例子
1 2 3 4 5 6 #ifndef A_H #define A_H typedef void (*pcb) (int a) ; void SetCallBackFun (int a, pcb callback) ;#endif
下面例子中在B中实现回调函数和设置回调函数,实际的调用会在A中
同步回调 1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> #include "A.h" void SetCallBackFun (int a, pcb callback) { printf ("A:start\n" ); callback(a); printf ("A:end\n" ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "A.h" void fCallBack (int a) { printf ("B:start\n" ); printf ("a = %d\n" ,a); sleep(5 ); printf ("B:end\n" ); } int main (void ) { SetCallBackFun(4 ,fCallBack); return 0 ; }
异步回调 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include "A.h" typedef struct parameter { int a ; pcb callback; }parameter; void * callback_thread (void *p1) { parameter* p = (parameter*)p1 ; sleep(5 ); p->callback(p->a); } void SetCallBackFun (int a, pcb callback) { printf ("A:start\n" ); parameter *p = malloc (sizeof (parameter)) ; p->a = a; p->callback = callback; pthread_t pid; pthread_create(&pid,NULL ,callback_thread,(void *) p); printf ("A:end\n" ); pthread_join(pid,NULL ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "A.h" void fCallBack (int a) { printf ("B:start\n" ); printf ("a = %d\n" ,a); sleep(5 ); printf ("B:end\n" ); } int main (void ) { SetCallBackFun(4 ,fCallBack); return 0 ; }
运行结果比较:
同步回调
异步回调
A:start B:start a = 4 B:end A:end
A:start A:end B:start a = 4 B:end
由执行结果可以看出:同步回调,A需要等待B执行完成才能执行A剩余的操作;异步回调,A刚执行B,不必等待B结束,就执行A剩余的操作,之后B的操作也随之end。
附录: https://blog.csdn.net/qq_31930499/article/details/80654472
https://www.runoob.com/w3cnote/c-callback-function.html