回调函数和钩子函数

回调函数,就是不直接调用,而是在函数参数中通过函数指针来调用。
正常情况下,A函数调用B函数:
A()
{
B( );
}
回调函数的例子看命令行的安装函数:
定义》》
ULONG CLI_InstallCmd(…, IN ULONG(*InteractiveProc)(PVECTOR_S *,ULONG), …)
调用》》
ulRet += CLI_InstallCmd(…, CLI_Config_Terminal, …);
这就是通过回调的方式调用了函数
ULONG CLI_Config_Terminal(PVECTOR_S * pMatchVec, ULONG ulUserID)
如果写成直接调用是这样
ULONG CLI_InstallCmd()
{
CLI_Config_Terminal();
}
那为什么要写成回调呢???
这是system-view命令的安装:
CLI_InstallCmd(…, CLI_Config_Terminal, …);
这是_list elements命令的安装:
CLI_InstallCmd(…, CLI_ListAllCmdElements, …);
这是header命令的安装:
CLI_InstallCmd(…, CLI_BannerInteractive, …);
假如不使用回调函数,那么只有system-view命令的时候函数是这样的:
ULONG CLI_InstallCmd()
{
CLI_Config_Terminal();
}
以后新增了_list elements命令,函数要变成这样:
ULONG CLI_InstallCmd()
{
CLI_Config_Terminal();
CLI_ListAllCmdElements();
}
再然后函数会变成这样:
ULONG CLI_InstallCmd()
{
CLI_Config_Terminal();
CLI_ListAllCmdElements();
CLI_BannerInteractive();
}
但是使用了回调函数,函数一直是这样:
ULONG CLI_InstallCmd(…, IN ULONG(*InteractiveProc)(PVECTOR_S *,ULONG), …)
另外,使用回调函数可以不立刻对函数指针进行处理,可以把这个函数指针再传给别的函数
那使用回调的缺点???
你在操作函数指针的时候,不知道它指向哪个函数,可能对调试造成困难。

以下转载自各位大神:
第1篇:
什么是回调函数?
简而言之,回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。

为什么要使用回调函数?
因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为 int )的被调用函数。

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

什么是钩子函数?
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。对每种类型的钩子由系统来维护一个钩子链,最近安装的钩子放在链的开始,而最先安装的钩子放在最后,也就是后加入的先获得控制权。

也可以这样,更容易理解:回调函数就好像是一个中断处理函数,系统在符合你设定的条件时自动调用。为此,你需要做三件事:
声明;
定义;
设置触发条件,就是在你的函数中把你的回调函数名称转化为地址作为一个参数,以便于系统调用。

回调函数是一个程序员不能显式调用的函数;通过将回调函数的地址传给调用者从而实现调用。回调函数使用是必要的,在我们想通过一个统一接口实现不同的内容,这时用回掉函数非常合适。比如,我们为几个不同的设备分别写了不同的显示函数:void TVshow(); void ComputerShow(); void NoteBookShow()…等等。这是我们想用一个统一的显示函数,我们这时就可以用回掉函数了。void show(void (*ptr)()); 使用时根据所传入的参数不同而调用不同的回调函数。

第2篇:
所谓回调函数,一般就是把函数的地址作为参数传进去,让调用的函数在内部可以调用这个函数。
例子:
void CALLBACK fun(){…} 这是一个函数,回调函数
void AAA(int a, Fun* p); 这是一个普通函数,但第二个参数是fun
AAA(5, fun);

钩子函数,严格算起来,也算是回调函数的一种。但钩子函数是针对的截取的,当你使用了钩子之后,每当触发到相对应的消息,系统就会先“执行你写的回调函数”。
即原本是:系统–>目标函数
使用钩子就变成:系统–>你写的回调函数–>目标函数

第3篇:
在消息处理机制中必不可少的一组CP,即回调和钩子。

钩子的概念源于Windows的消息处理机制,通过设置钩子,应用程序可以对所有的消息事件进行拦截,然后执行钩子函数,对消息进行想要的处理方式。

接下来是一段js代码,主要用于给btn设置点击的钩子函数。

let btn = document.getElementById("btn");
btn.onclick = () => {
    console.log("i'm a hook");
}

钩子是在捕获消息的时候立即执行钩子函数。

下面是一段给btn添加click的监听器。

btn.addEventListener("click",() =>{
    console.log(this.onclick);//undefined
});

这是给btn绑定了一个监听器,后面那个函数是它的回调函数,因为消息捕获的过程我们并不能参与,而在捕获执行完毕的时候,回调函数才会执行,我们可以把对消息的处理写在回调函数里。

js由于自身的特殊性(单线程),因而在代码里充满各式各样的异步操作,因此回调函数也是铺天盖地,上面的两段代码都是异步的。

回调函数和钩子函数的区别
根本上,他们都是为了捕获消息而生的,但是钩子函数在捕获消息的第一时间就会执行,而回调函数是在整个捕获过程结束时,最后一个被执行的。

回调函数其实就是调用者把回调函数的函数指针传递给调用函数,当调用函数执行完毕时,通过函数指针来调用回调函数。

猜你喜欢

转载自blog.csdn.net/wanggong_1991/article/details/86699592