【发布时间】:2010-05-07 23:47:42
【问题描述】:
所以我想知道它们是如何工作的。为了解释我所说的“函数调用者”的意思,我的意思是glutTimerFunc 的一个很好的例子,它能够将函数作为参数接收并调用它,即使它不知道它已被声明。这是怎么做到的?
【问题讨论】:
所以我想知道它们是如何工作的。为了解释我所说的“函数调用者”的意思,我的意思是glutTimerFunc 的一个很好的例子,它能够将函数作为参数接收并调用它,即使它不知道它已被声明。这是怎么做到的?
【问题讨论】:
您所说的称为callback,并在C 和C++ 中使用function pointers 实现。
既然你提到了过剩,那我们直接从freeglut源代码中举一个真实的例子。我将使用glutIdleFunc 而不是 glutTimerFunc,因为代码更简单。
在 glut 中,空闲函数回调(您提供给 glutIdleFunc 的内容)是一个指向不带参数也不返回任何内容的函数的指针。 typedef 用于给这样的函数类型命名:
typedef void (* FGCBIdle)( void );
这里,FGCBIdle(FreeGlut CallBack Idle 的缩写)被定义为一个指向不带参数且返回类型为 void 的函数的指针。这只是一个类型定义,使编写表达式更容易,它不分配任何存储空间。
Freeglut 有一个名为 SFG_State 的结构,其中包含各种设置。该结构的部分定义是:
struct tagSFG_State
{
/* stuff */
FGCBIdle IdleCallback; /* The global idle callback */
/* stuff */
};
该结构包含一个 FGCBIdle 类型的变量,我们建立它是特定函数指针的另一个名称。您可以将 IdleCallback 字段设置为指向用户使用 glutIdleFunc 函数提供的函数的地址。该函数的(简化)定义是:
void glutIdleFunc( void (* callback)( void ) )
{
fgState.IdleCallback = callback;
}
这里,fgState 是一个 SFG_State 变量。如您所见,glutIdleFunc 有一个参数,它是一个函数指针,指向一个不带参数且不返回任何内容的函数,该参数的名称是回调。在函数内部,全局 fgState 变量中的 IdleCallback 设置为用户提供的回调。当您调用 glutIdleFunc 函数时,您传递的是您自己的函数的名称(例如 glutIdleFunc(myIdle)),但您真正传递的是函数的地址。
稍后,在 glutMainLoop 启动的大过剩事件处理循环中,您会发现以下代码:
if( fgState.IdleCallback )
{
/* stuff */
fgState.IdleCallback( );
}
如果用户提供的空闲回调可用,则在循环中调用它。如果您查看我文章开头的函数指针教程,您会更好地理解语法,但我希望现在一般概念更有意义。
【讨论】:
参数是指向函数的指针。调用者有责任确保函数声明符合要求(例如,参数的数量和类型、调用约定)。
【讨论】:
作为参数传递的函数作为函数指针传递。
在编译后的代码中,函数只不过是 CPU 可以引导执行的地址。当您传递函数指针时,编译器(以及后来的链接器)将正确的地址插入到调用中。
函数参数必须完全匹配,因为执行代码只会将值压入堆栈(或寄存器,取决于架构)并期望弹出(读出)返回值。
【讨论】: