函数指针的重要用途——回调函数

什么是回调函数? 粗暴的说,如果一个函数作为另一个函数的参数传入,这种函数就可以称为回调函数(这句话并不严谨,但为了说明问题可以这么理解)。C语言里面,一般就是一个函数的参数列表中有函数指针,函数指针指向的函数就是一个回调函数。
为什么要有回调函数? 那为什么不直接在函数体内调用,而非要把函数指针作为参数呢?
举一个例子:系统提供一个排序函数sort(int a[ ]),排序函数默认升序,但如果我们想要降序排列呢?那系统还要提供一个降序版本?
显然,系统可以提供这样一个接口sort(int a[ ], void(*p)(int*) ),后者是一个指向排序方法的函数指针。用户可以自行定义排序方法。即,我们可以认为,回调函数有以下的功能:

  • 一个接口,可以实现不同的功能。这种思想不就是多态吗?本质上还是为了实现地址的晚绑定。C++中的仿函数,其实是对函数指针做了某种程度的简化,使用户使用更简单罢了,使用到的思想是一样的。
  • 通过回调函数可以修改一个黑盒子内部默认的功能,这也是业务上经常用的。
Linux操作系统用到了大量回调的思想,比如对于不同厂家提供的驱动,厂家按照Linux提供的接口标准编写自己的方法,而Linux接口的参数列表中就有指向对应方法的函数指针,这样尽管厂家不同,Linux也可以使用。
再举一个例子,默认情况下,当我们按下CTRL + C时,进程会终止。那我们想改变这样的默认行为怎么办,linux提供了signal这样一个接口。
#include void (*signal(int sig, void (*func)(int)))(int);

第一个参数是信号的编号,此处的ctrl + C对应的是2号信号,第二个参数就是一个函数指针,指向用户自己提供的方法。
【函数指针的重要用途——回调函数】如下面的这段代码:
#include #include #include void mysignal(int signo) { printf("catch a signal! %d\n", signo); }int main() { signal(2, mysignal); while(1) { printf("hello world!\n"); sleep(1); } return 0; }

这段代码中,使用signal函数注册了一个新的方法,当按下ctrl + C时,不再默认终止进程,而是输出catch a signal! 2。效果如下:
函数指针的重要用途——回调函数
文章图片

也就是说,系统提供接口用到了回调函数,用户定义该函数,实现了用户所需要的功能。这也是回调函数的主要应用方式。

    推荐阅读