C API函数回调到C++成员函数代码

10

我正在使用FMOD API,它确实是一个C API。

并不是说这有什么不好。只是它与C++代码的接口不太好。

例如,使用

FMOD_Channel_SetCallback( channel, callbackFunc ) ;
它需要一个C风格的函数作为callbackFunc,但我想传递一个类的成员函数给它。最终,我采用了Win32技巧,将成员函数变为静态函数。这样就可以作为回调函数进入FMOD了。现在我必须修改我的代码,使一些成员变量成为静态的,以适应FMOD的C风格。我想知道是否有可能在FMOD中或者有没有方法将回调链接到特定的C++对象实例成员函数(而不是静态函数),这样会更加顺畅。
5个回答

13

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

你需要创建一个跳板函数(不确定回调的签名,所以这里只是随意写了一些东西)。

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

一个问题是对象指针来自哪里。希望fmod会给你一个通用的上下文值,在回调被调用时会提供给你(然后你可以传入对象指针)。

如果没有,你只需要将其设置为全局变量以访问它。


1
+1 是的,你确实需要制作一个蹦床,但它们非常棒(如果你想避免全局变量和所有这些)! :-( 如果 API 一开始就被正确设计了... - C. K. Young
1
你还需要考虑如果C++成员函数抛出异常该怎么办。而这个“trampoline”术语是从哪里来的? - anon
2
@NeilButterworth - 我不记得我最初在哪里听说这被描述为“蹦床”,但我使用的一个参考是维基百科(http://en.wikipedia.org/wiki/Trampoline_%28computers%29)`当将代码片段与不兼容的调用约定进行接口时,会使用蹦床将调用者的约定转换为被调用者的约定。` - R Samuel Klatchko
2
谢谢链接,Samuel Klatchko先生。所以基本上另一个单词是“thunk”,我想。 - anon
1
@NeilButterworth - 绝对的 - 我认为“trampoline”和“thunk”是同义词。 - R Samuel Klatchko

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

2
有一种非便携的而且相当hackish的解决方案,它具有至少是线程安全的优点,而“跳板”方法则不具备此优点。
您可以动态生成实际的函数机器代码。基本思路是,您拥有一个调用回调函数的模板,该模板接受对象指针和成员函数指针,并为您提供一个堆内存块,您可以将其作为C回调函数传递给库,当调用时,它将转而调用该对象上的成员函数。
这很凌乱,并且您必须为任何新平台(任何时候调用约定更改)提供实现,但它起作用并且是线程安全的。(当然,您还必须注意DEP)。另一个线程安全的解决方案是使用线程局部存储(假设您知道回调将在与所做的调用相同的线程上发生)。
请参见http : //www.codeproject.com/KB/cpp/GenericThunks.aspx,了解如何生成thunk的示例。

1

在我的看法中,仅使用函数指针(而没有额外的单独对象指针)作为C回调是一种有缺陷的设计。

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


1
请向FMOD人员建议这个!拜托! - bobobobo
1
@bobobobo:看看Denis的回答。我认为API已经支持这个功能了(显然他比我更深入地研究了FMOD :-P)。我会保留我的答案,作为其他API设计者的警示故事,但至少你现在有一个解决方案了。 - C. K. Young

0

你需要使用一个蹦床并将指向你想要调用成员函数的对象的指针存储在全局或静态变量中,例如:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接