【问题标题】:C API function callbacks into C++ member function codeC API 函数回调到 C++ 成员函数代码
【发布时间】:2010-03-11 05:09:59
【问题描述】:

所以,我使用的是 FMOD api,它确实是一个 C api。

这不是坏事或任何事情。只是它与 C++ 代码的接口不太好。

例如,使用

FMOD_Channel_SetCallback( channel, callbackFunc ) ;

它想要callbackFunc 的 C 风格函数,但我想将它传递给一个类的成员函数。

我最终为此使用了 Win32 技巧,使成员函数成为静态的。然后它作为 FMOD 的回调。

现在我必须破解我的代码以使一些成员静态化,以说明 FMOD 的 C 特性。

我想知道它是否可以在 FMOD 中使用,或者是否有办法将回调链接到特定 C++ 对象的实例成员函数(不是静态函数)。会流畅很多。

【问题讨论】:

    标签: c++ c fmod static-functions


    【解决方案1】:

    您不能直接传递成员函数。成员函数有隐式参数this 而C 函数没有。

    你需要创建一个蹦床(不确定回调的签名,所以在这里随机做一些事情)。

    extern "C" int fmod_callback( ... args ...)
    {
        return object->member();
    }
    

    一个问题是该对象指针从何而来。希望 fmod 为您提供一个通用的上下文值,当您进行回调时将提供给您(然后您可以传入对象指针)。

    如果没有,您只需将其设为全局即可访问它。

    【讨论】:

    • +1 是的,你必须做一个蹦床,但它们太粗糙了(如果你想避免全局变量等等)! :-( 如果 API 一开始就设计正确....
    • 您还需要担心如果 C++ 成员函数抛出异常该怎么办。而这个“蹦床”一词是从哪里来的?
    • @NeilButterworth - 我不记得我第一次听到这被描述为“蹦床”的地方,但我使用的一个参考是维基百科 (en.wikipedia.org/wiki/Trampoline_%28computers%29) When interfacing pieces of code with incompatible calling conventions, a trampoline is used to convert the caller's convention into the callee's convention.
    • @R Samuel Klatchko 感谢您的链接。所以基本上我认为“thunk”的另一个词。
    • @NeilButterworth - 绝对 - 我认为“蹦床”和“thunk”是同义词。
    【解决方案2】:

    我猜它应该像这样工作:
    您可以通过调用FMOD_Channel_SetUserData 将一些用户数据分配给通道。此用户数据应该是指向处理事件的 C++ 对象的指针。 然后你应该编写 C 风格的回调,通过调用 FMOD_Channel_GetUserData 提取该对象,然后在该对象上调用你的 C++ 实例方法。

    【讨论】:

      【解决方案3】:

      有一个不可移植且相当老套的解决方案,其优点是至少是线程安全的,而“蹦床”方法则不是。

      您可以即时生成实际的功能机器代码。基本思想是,您有一个回调函数模板,该模板接受一个对象指针和一个成员函数指针,并为您提供一块堆内存,您可以将其作为 C 回调函数传递给库,即将在被调用时转身并调用该对象上的成员函数。

      这很混乱,您必须为任何新平台提供一个实现(任何时候调用约定发生变化),但它可以工作,是线程安全的。 (当然,您还必须注意 DEP)。另一个线程安全的解决方案是使用线程本地存储(假设您知道回调将发生在与您进行的调用相同的线程上)。

      请参阅 http://www.codeproject.com/KB/cpp/GenericThunks.aspx 了解如何生成 thunk 的示例。

      【讨论】:

        【解决方案4】:

        在我看来,仅对 C 回调使用函数指针(而不使用额外的单独对象指针)是一种错误的设计。

        如果函数是 FMOD_Channel_SetCallback(channel, callbackFunc, callbackObj),那么您的静态方法只需获取对象的一个​​实例,然后调用 callbackObj->func()(显然可以是非静态的)。

        【讨论】:

        • 把这个推荐给 FMOD 的人!请!
        • @bobobobo:见丹尼斯的回答。我认为 API 已经支持这一点(显然他对 FMOD 的研究比我研究的要多:-P)。我会继续我的回答,作为对其他 API 设计者的警示,但是,至少你有一个解决方案。
        【解决方案5】:

        您需要使用蹦床并将指针存储到要在全局或静态变量中调用成员函数的对象,即

        Object *x;
        void callback_trampoline() { x->foobar(); }
        ...
        FMOD_Channel_SetCallback(CHANNEL, callback_trampoline);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-08-08
          • 1970-01-01
          • 2012-03-04
          • 2010-11-03
          • 1970-01-01
          • 1970-01-01
          • 2013-02-15
          • 1970-01-01
          相关资源
          最近更新 更多