1. The call back declaration:
回调函数是一个程序员不能显式调用的函数;通过将回调函数的地址传给调用者从而实现调用。
要实现回调,必须首先定义函数指针。尽管定义的语法有点不可思议,
但如果你熟悉函数声明的一般方法,便会发现函数指针的声明与函数声明非常类似。
请看下面的例子:
void f();//函数原型上面的语句声明了一个函数,没有输入参数并返回void。
那么函数指针的声明方法如下:
void (*)();
让我们来分析一下,左边圆括弧中的星号是函数指针声明的关键。
另外两个元素是函数的返回类型和由边圆括弧中的入口参数。
注意本例中还没有创建指针变量-只是声明了变量类型。
目前可以用这个变量类型来创建类型定义名及用sizeof表达式获得函数指针的大小:
//获得函数指针的大小
unsigned psize = sizeof(void (*)());
//为函数指针声明类型定义
typedef void (*pfv)();
pfv是一个函数指针,它指向的函数没有输入参数,返回类行为void。
使用这个类型定义名可以隐藏复杂的函数指针语法。
指针变量应该有一个变量名:
void (*p)(); //p是指向某函数的指针
p是指向某函数的指针,该函数无输入参数,返回值的类型为void。左边圆括弧里星号后的就是指针变量名。
有了指针变量便可以赋值,值的内容是署名匹配的函数名和返回类型。例如:
void func()
{
/* do something */
}
p = func;
p的赋值可以不同,但一定要是函数的地址,并且署名和返回类型相同。
2. 传递回调函数的地址给调用者现在可以将p传递给另一个函数- caller(),
它将调用p指向的函数,而此函数名是未知的:
void caller(void(*ptr)())
{
ptr(); /* 调用ptr指向的函数 */
}
void func();
int main()
{
p = func;
caller(p); /* 传递函数地址到调用者 */
}
如果赋了不同的值给p,那么调用者将调用不同地址的函数。赋值可以发生在运行时,这样使你能实现动态绑定。
3. 调用规范到目前为止,我们只讨论了函数指针及回调而没有去注意ansi c/c++的编译器规范。
许多编译器有几种调用规范。如在visual c++中,可以在函数类型前加_cdecl,
_stdcall或者_pascal来表示其调用规范。c++ builder也支持_fastcall调用规范。
调用规范影响编译器产生的给定函数名,参数传递的顺序,堆栈清理责任以及参数传递机制。
将调用规范看成是函数类型的一部分是很重要的;不能用不兼容的调用规范将地址赋值给函数指针。例如:
//被调用函数是以int为参数,以int为返回值
__stdcall int callee(int); //调用函数以函数指针为参数
void caller(__cdecl int(*ptr)(int)); //在p中企图存储被调用函数地址的非法操作
__cdecl int(*p)(int) = callee; //出错指针p和callee()的类型不兼容,因为它们有不同的调用规范。因此不能将被调用者的地址赋值给指针p,尽管两者有相同的返回值和参数列。
发表者:james_razor callback function其实就是c语言中,strategy模式的一种实现。
阅读(1163) | 评论(0) | 转发(0) |