【问题标题】:Function callers (callbacks) in C?C中的函数调用者(回调)?
【发布时间】:2010-05-07 23:47:42
【问题描述】:

所以我想知道它们是如何工作的。为了解释我所说的“函数调用者”的意思,我的意思是glutTimerFunc 的一个很好的例子,它能够将函数作为参数接收并调用它,即使它不知道它已被声明。这是怎么做到的?

【问题讨论】:

    标签: c function


    【解决方案1】:

    您所说的称为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( );
    }
    

    如果用户提供的空闲回调可用,则在循环中调用它。如果您查看我文章开头的函数指针教程,您会更好地理解语法,但我希望现在一般概念更有意义。

    【讨论】:

      【解决方案2】:

      参数是指向函数的指针。调用者有责任确保函数声明符合要求(例如,参数的数量和类型、调用约定)。

      【讨论】:

        【解决方案3】:

        作为参数传递的函数作为函数指针传递。

        在编译后的代码中,函数只不过是 CPU 可以引导执行的地址。当您传递函数指针时,编译器(以及后来的链接器)将正确的地址插入到调用中。

        函数参数必须完全匹配,因为执行代码只会将值压入堆栈(或寄存器,取决于架构)并期望弹出(读出)返回值。

        【讨论】:

          猜你喜欢
          • 2023-01-23
          • 2011-05-07
          • 1970-01-01
          • 2011-07-26
          • 1970-01-01
          • 2011-01-18
          • 1970-01-01
          • 2012-11-29
          • 2012-06-23
          相关资源
          最近更新 更多