In C++, is it safe/portable to use static member function pointer for C API callbacks?

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?


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

AC 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.

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

Make your C ABI callbacks extern "C" .


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

3.5 "Program and linkage":

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]

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

And

7.5 "Linkage specifications":

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

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.


After searching and several breaks while attacking other problems, I found an answer which is clear and succinct (for standardese, anyway):

Calling a function through an expression whose function type has a language linkage that is different from the language linkage of the function type of the called function's definition is undefined. [5.2.2/1]

I still maintain that it is problematic at a fundamental level to use text from the C++ standard to define the behavior of a C library compiled with a C compiler, and exactly how that interlanguage interoperability works is very implementation-specific; however, this is the closest I think either standard can (currently) hope to define such interaction.

In particular, this is undefined behavior (and isn't using a C library so that issue doesn't arise):

void call(void (*pf)()) { pf(); } // pf() is the UB
extern "C" void f();
int main() { call(f); }
// though I'm unsure if a diagnostic is required for call(f)

Comeau does give a diagnostic at call(f) (though it can do that even if the diagnostic isn't required).

This isn't undefined behavior, and shows how to include language linkage in a function pointer type (which is through a typedef):

extern "C" typedef void F();
void call(F* pf) { pf(); }
extern "C" void f();
int main() { call(f); }

Or could be written:

extern "C" {
typedef void F();
void f();
}
void call(F* pf) { pf(); }
int main() { call(f); }

For all the Windows C++ compilers that I'm aware of, the answer is yes, but nothing in the language standard guarantees this. I wouldn't let that stop you however, it's a very common way of implementing callbacks using C++ - you may find you need to declare the static functions as WINAPI however. This is taken from an old threading library of my own:

class Thread {
   ...
   static DWORD WINAPI ThreadFunction( void * args );
};

where this is the callback use by te Windows threading API.

链接地址: http://www.djcxy.com/p/96364.html

上一篇: 如何从Java中的静态方法访问非静态成员?

下一篇: 在C ++中,对C API回调使用静态成员函数指针是否安全/可移植?