回调函数执行过程分析
学号:SA*****200
回调的过程
将函数作为参数,传入某一外部函数,以便该外部函数可以调用此函数来完成某些任务,这样的函数就称为回调函数(CallBack,call-then-back)
上图是一个示例,应用程序在调用某一库函数时,通过将函数地址作为参数传递的方式,指定了一个回调函数。库函数执行过程中,会调用这一函数,来完成应用程序的请求。一般回调函数都是和应用程序处于同一抽象层,这样就形成了一个:高层调用底层,底层再反过来调用高层的过程。
事实上,回调不仅可以用于在应用程序和库函数之间,把库函数换成别的中间函数也行。
回调的优势
回调函数为应用提供了很大的灵活性、可拓展性。
一方面,同一个接口(即中间函数),根据起始函数传入的参数(即回调函数地址)不同,可以表现出不同的行为,这体现了多态的思想。
另一方面,采用这种方法,也满足了开闭原则,即你可以在不修改中间函数源代码的情况下,仅通过修改或者添加回调函数,便可以变更接口的行为。
一个回调函数执行的例子
下面是一个回调函数执行的例子(meun.c 中执行过程与此相仿)
![]() |
![]() |
现有一个接口 getOddNum,可以给定任意整数,它返回一个奇数。至于得到奇数的方式,则由用户自定义,比如是采用 2K+1 还是 4k+1 的形式,由传入的回调函数确定。
main 函数以 doubleNum 为参数调用 getOddNum 时,会把其地址传入 rsi 寄存器:movl $_Z9doubleNumi, %esi,然后就调用接口, call _Z9getOddNumiPFiiE,开始接口的处理过程了。
在 getOddNum 函数中,分配栈帧后,会 call *%rsi,也即调用 rsi 寄存器中的地址指向的函数,而 rsi 中存放的,正是在 main 函数中放入的 doubleNum 的入口地址。可见,确实是在 getOddNum 函数中调用的回调函数。
进入 doubleNum 函数后,它会把 rdi 寄存器中的参数加上自身后返回,返回到 getOddNum 函数中,然后 getOddNum 函数对 rax 寄存器中的返回值加一,把 rsp 指向 main 函数的栈顶,然后返回。此时,main 函数便完成了一次对接口 getOddNum 的调用,传入3,得到了奇数 7。
想以 4k+1 的方式得到奇数,也不需要改动接口 getOddNum 的代码,只需要添加一个回调函数 fourTimesNum 即可,调用的方式也不变,简单满足了开闭原则。

