在 C++ 中,将静态成员函数指针用于 C API 回调是否安全/可移植?

2022-01-03 00:00:00 callback portability c++

在 C++ 中,将静态成员函数指针用于 C API 回调是否安全/可移植?静态成员函数的 ABI 和 C 函数一样吗?

In C++, is it safe/portable to use static member function pointer for C API callbacks? Is the ABI of a static member function the same as a C function?

推荐答案

根据 C++ 标准,它是不安全的.如此SO发布中所述:

It is not safe per the C++ standard. As stated in this SO posting:

在 C++ 中实现的 C 回调函数必须是 extern C".它似乎在类中作为静态函数工作,因为类静态函数通常使用与 C 函数相同的调用约定.但是,这样做是一个等待发生的错误(请参阅下面的评论),所以请不要 - 通过 extern C"代替包装器.

A C callback function implemented in C++ must be extern "C". It may seem to work as a static function in a class because class-static functions often use the same calling convention as a C function. However, doing that is a bug waiting to happen (see comments below), so please don't - go through an extern "C" wrapper instead.

并且根据 Martin York 在该答案中的评论,尝试这样做存在现实世界的问题在某些平台上.

And according to comments made by Martin York in that answer there are real-world problems trying to do so on some platforms.

使您的 C ABI 回调 extern "C".

Make your C ABI callbacks extern "C".

从标准中添加一些支持引用(强调我的):

Adding some supporting quotes from the standard (emphasis mine):

3.5程序和链接":

在类型的所有调整之后(在此期间typedefs(7.1.3)被它们的定义替换),所有引用给定对象或函数的声明指定的类型应该是相同的,除了数组对象的声明可以指定不同的数组类型,这些类型因是否存在主数组绑定(8.3.4)而异.在类型标识上违反此规则不需要诊断.[3.5/10]

After all adjustments of types (during which typedefs (7.1.3) are replaced by their definitions), the types specified by all declarations referring to a given object or function shall be identical, except that declarations for an array object can specify array types that differ by the presence or absence of a major array bound (8.3.4). A violation of this rule on type identity does not require a diagnostic. [3.5/10]

[注意:可以使用链接规范 (7.5) 实现与非 C++ 声明的链接.] [3.5/11]

[Note: linkage to non-C++ declarations can be achieved using a linkage-specification (7.5). ] [3.5/11]

7.5连杆规格":

... 具有不同语言链接的两种函数类型是不同类型,即使它们在其他方面完全相同.[7.5/1]

... Two function types with different language linkages are distinct types even if they are otherwise identical. [7.5/1]

因此,如果进行回调的代码使用 C 语言绑定进行回调,则回调目标(在 C++ 程序中)也必须如此.

So if the code making the callback is using C language bindings for the callback, then the callback target (in the C++ program) must as well.

相关文章