【发布时间】:2017-03-12 14:59:06
【问题描述】:
我有一个第三方 C API,它需要一个 __stdcall 回调函数。
我的代码有一个外部提供的 __cdecl 回调函数。
我无法将函数指针传递给 C-API,因为它们被视为不同的类型。
绕过类型系统并使用reinterpret_cast<> 自然会导致运行时错误。
这是来自here的示例:
// C-API
// the stdcall function pointer type:
typedef CTMuint(__stdcall *CTMwritefn)(const void *aBuf, CTMuint aCount, void *aUserData);
// A function needing the callback:
CTMEXPORT void __stdcall ctmSaveCustom(CTMcontext aContext, CTMwritefn aWriteFn, void *aUserData, int *newvertexindex);
^^^^^^^^^^^^^^^^^^^
//////////////////////////////////////////////////////////////////////////////
// C++
CTMuint __cdecl my_func(const void *aBuf, CTMuint aCount, void *aUserData);
// I want to call here:
ctmSaveCustom(context, my_func, &my_data, nullptr);
// ^^^^^^^
有没有一种方法可以安全地将具有一种调用约定的函数转换和/或包装成另一种?
我确实找到了一种方法,方法是传递一个调用 second 捕获 lambda 的强制转换的无捕获 lambda。第一个作为回调传递,第二个通过void* user_data。这有效并且是类型安全的。但是对于看起来如此简单的事情来说,它是相当复杂的。
【问题讨论】:
-
你不能只创建一个 cdecl 包装器来将调用转发到你的真实回调吗?
-
@krzaq:你会怎么做?它并不像看起来那么明显......我将添加一个示例。
-
你能否——除了函数指针——也传递“用户数据”(通常是
void *)?否则,包装函数在线程安全/多个回调方面会有点麻烦。 -
@DanielJour:是的,请参阅上面的扩展问题和解决方法。
-
但对于看似如此简单的事情却相当复杂 -- 你为什么认为它“简单”?调用约定不仅仅是一个关键字。它定义了如何在低级别传递参数和返回值。一个函数想要一个
__stdcall函数,没有办法绕过它——它就是这样。
标签: c++ function-pointers calling-convention stdcall cdecl