回调函数

回调函数,就是,把被调用函数(回调函数)的地址作为调用者函数的一个参数,从而在适当的条件下可以执行它.如信号处理函数,我们先定义一个信息处理函数,然后注册这个函数,在信号发生时就会执行回调函数.

如linux中的信号函数:signal

#include<signal.h>
void(*signal(int signo,void (*func)(int))) (int)

signal的函数值:若成功则返回信号之前的信号处理函数地址,该信号处理函数返回值为void,它有一个int类型参数。若失败,则返回SIG_ERR

signal的参数:signo为信号名,而func为一个函数指针,它有一个int参数,其实就是信号名。

使用typedef可以使上面的声明简化:

typedef void Sigfun(int);

Sigfun *signal(int,Sigfun *)


在头文件中:

#define SIG_ERR (void (*)()) -1

这个signal也是返回函数的一个例子。

程序员面试宝典中的一个例子:
int(*(*F)(int ,int))(int)
F是一个函数指针,它指向的函数有两个整型参数,并且返回一个函数指针。返回的函数指针指向返回int类型并且有一个int类型的参数。这种形式的声明一般放在结构体中,或C++中的类中。而在外而实现这个函数,然后把这个地址把结构体实例的F赋值,然后调用这个函数。


若不要返回函数指针则声明形式相对简单:

假设返回一个int类型变量:

int func(int arg1,void(*callback)(void *),void *p)

这里的P一般是给callback的参数列表。

typedef void(*callback)(void *);

int func(int arg1,callback funp,void *p);

#include "stdio.h"
int func(int arg1,void(*callback)(void *),void *p);//	这里的P一般是给callback的参数列表。
typedef void(*callback)(void *);
int func(int arg1,callback funp,void *p);
typedef struct tocallback{
	int n;
	char buff[16];	
}tocallback;

int func(int arg1,callback funp,void *p)
{
	if(1==arg1)
	{
		funp(p);
		return 0;
	}	
	printf("%s\n","in func arg1!=1");
	return -1;
}

/*
回调函数
*/
void mycallback(void *src)
{
	tocallback *p=(tocallback*)src;	
	if(NULL==src)
		return;
	
	printf("%d,%s\n",p->n,p->buff);
}

void main()
{
    tocallback par;
    par.n=4;
    strncpy(par.buff,"hello",16);
    func(0,mycallback,&par);
func(1,mycallback,&par);
}

 



回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

⑴定义一个回调函数

⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;

⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。

因为可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。简而言之,回调函数就是允许用户把需要调用的方法的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。

回调函数在实际中有什么作用?先假设有这样一种情况:我们要编写一个库,它提供了某些排序算法的实现(如冒泡排序快速排序shell排序、shake排序等等),为了能让库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,能让库可用于多种数据类型(int、float、string),此时,该怎么办呢?可以使用函数指针,并进行回调。

回调可用于通知机制。例如,有时要在A程序中设置一个计时器,每到一定时间,A程序会得到相应的通知,但通知机制的实现者对A程序一无所知。那么,就需一个具有特定原型的函数指针进行回调,通知A程序事件已经发生。实际上,API使用一个回调函数SetTimer()来通知计时器。如果没有提供回调函数,它还会把一个消息发往程序的消息队列

另一个使用回调机制的API函数是EnumWindow(),它枚举屏幕上所有的顶层窗口,每个窗口都可以通过它调用另一个程序提供的函数,并传递窗口的处理程序。例如:如果被调用者返回一个值,就继续进行迭代;否则,退出。EnumWindow()并不关心被调用者在何处,也不关心被调用者用它传递的处理程序做了什么,它只关心返回值,因为基于返回值,它将继续执行或退出。

不管怎么说,回调函数是继承自C语言的。在C++中,应只在与C代码建立接口或与已有的回调接口打交道时,才使用回调函数。除了上述情况,在C++中应使用虚拟方法或函数符(functor),而不是回调函数。

 

 C.回调函数与API函数

    回调和API非常接近,他们的共性都是跨层调用的函数。但区别是API是低层提供给高层的调用,一般这个函数对高层都是已知的;而回调正好相反,他是高层提供给底层的调用,对于低层他是未知的,必须由高层进行安装,这个安装函数其实就是一个低层提供的API,安装后低层不知道这个回调的名字,但它通过一个函数指针来保存这个回调函数,在需要调用时,只需引用这个函数指针和相关的参数指针。

 

其实:回调就是该函数写在高层,低层通过一个函数指针保存这个函数,在某个事件的触发下,低层通过该函数指针调用高层那个函数。

回调函数。回调函数的原理是使用函数指针实现类似软中断的概念。比如在上层的两个函数A和B,把自己的函数指针传给了C,C通过调用A和B的函数指针达到“当做了什么,通知上层来调用A或者B”的目的。
从更底层的角度上,代码之间都是在一段程序里面或者可以理解为一致代码段的跳转。通过标准的callret就可以实现的。

2,中断处理函数。
首先,要了解CPU的底层处理机制。CPU对中断,错误的处理有三种:
1,错误(fault),这种处理方式会跳到错误的处理程序中,当从错误的处理程序返回,会重新执行当前的指令(再执行一遍出错的那条指令)
2,陷阱(trap),也会跳到陷阱的处理函数中,当从陷阱函数中返回,执行下一条指令。
3,异常(abort),异常终止当前程序。

其实对于中断,类似于trap的过程。表面看来,他和回调函数都是一样的概念,都是,
发生中断--->跳到中断处理函数里面--->回到中断点下一条--->清中断,
     但是中断与回调的区别和联系是,
1,中断可能实现不同优先级代码的跳转。比如我发生了软中断,比如接到一个信号,我就要跳到信号处理函数里面执行,但是本身实现信号处理函数跳转的,是一个内核级的代码段。
2,有些中断,是通过回调实现的,比如windows的视频采集,就是一个帧中断,但是你注册给上层的是一个回调,
3,关于中断的可重入,这个和回调不同,具体这又是一个话题了。
4,应用场合不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值