C语言函数指针与回调函数

在层次化程序设计中,上层模块可以直接调用下层模块的函数,而下层模块一般不能直接调用上层模块的函数。而实际情况中却常常存在层间相互依赖的情况,即层间相互调用函数,例如,层B的状态变化需要通知层A或者引起层B的状态变化,为了避免这种相互依赖,可以使用回调函数。假设层A位于层B的上层,层A调用层B的函数,称层A为caller,层B中被调用的函数被称为callee,层A中被callee回调的函数称为callbacker。

1. 回调函数

回调函数是通过caller向callee传递callbacker的函数指针实现,当在callee中callbacker被调用时,称为发生回调,而callbacker则称为回调函数。callee无需关心callbacker的实现细节和所处理的具体的数据类型,仅需知道callbacker的原型即可,而callbacker的实现由caller负责,其中包括实现细节(算法)和数据类型。

回调函数可以实现动态绑定,即通过在运行时向callee传递不同的函数指针,从而调用不同的函数。例如,排序算法中需要按某种规则比较数据,callee无需知道数据比较的方法以及数据的类型,而仅仅关心比较数据的个数以及比较结果的含义,具体的比较操作由callbacker负责,数据类型可以是原始数据类型也可以是结构体类型。

回调可以实现消息通知和事件驱动,比如callee中发生某个事件时,需要通知caller或者需要caller完成某种功能,则可以通过回调机制实现。

2. 函数指针

回调机制是通过传递函数指针实现,而函数指针则是指向函数的指针,函数指针的定义可以使用两种形式:

(1)直接定义

函数返回类型 (*函数指针名)(形参表);

(2)使用typedef

typedef 函数返回类型 (*新类型名)(形参表);

新类型名 函数指针名;

int add_int(int a, int b){return a+b;}

int (*pfunc)(int x, int y);

pfun = add_int;//或者&add_int

typedef int (*PFUNC)(int x, int y);

PFUNC pfunx;

pfunx = &add_int;

3. 返回函数指针的函数

即函数的返回值是一个函数指针,也可以有两种定义形式:

(1)直接定义

函数返回类型 (*函数名(形参表1))(形参表2){......}

定义了一个名称由“函数名”标识的函数,其参数由“形参表1”标识,该函数返回一个函数指针,指向一个由“函数返回类型”标识返回类型、参数个数以及类型符合“形参表2”的函数。

(2)使用typedef

typedef 函数返回类型 (*新类型名)(形参表2);

新类型名 函数名(形参表1){......}

实例:

void (*signal(int sig, void (*func)(int)))(int);

函数名:signal

功能:指定处理信号的函数,sig指定信号,func为处理该信号的函数,具有一个整型的参数

返回值:为一个函数指针,指向一个具有一个整型参数、返回值类型为void的函数,该函数参数类型以及返回值类型与func函数一致;即返回该信号之前的处理函数

#include <signal.h>

char tmpfilename [L_tmpnam];

void terminate (int param)
{
  printf ("Terminating program...\n");
  remove (tmpfilename);//移除临时文件
  exit(1);
}

int main(void)
{
 void (*prev_fn)(int);//定义函数指针
 FILE *fp;

prev_fn = signal (SIGTERM,terminate);//为SIGTERM信号指定处理函数terminate

tmpnam (tmpfilename);//生成临时文件名并保存在tmpfilename中

fp = fopen(tmpfilename, "w+");
 fprintf(fp, "test");
 fclose(fp);

raise(SIGTERM);//生成SIGTERM信号并通知进程

if (prev_fn==SIG_IGN) signal (SIGTERM,SIG_IGN);//重新设定默认处理函数

return 0;
}

4. 函数指针数组

指向一组有相同返回类型以及参数个数和顺序的函数,常用来替换switch/if结构,也可以有两种定义形式:

(1)直接定义

函数返回类型 (*函数指针数组名[N])(形参表);

(2)使用typedef

typedef 函数返回类型 (*新类型名)(形参表);

新类型名 函数指针数组名[N];

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/4f68ca919a9109372ac92d6bf68bc651.html