static vs extern"C"/"C++"

Gio*_*hal 22 c++ function-pointers static-members linkage extern-c

静态成员函数和extern"C"链接函数之间有什么区别?例如,在C++中使用"makecontext"时,我需要传递一个指向函数的指针.谷歌建议使用extern"C"链接,因为"makecontext"是C.但我发现使用静态工作也是如此.我只是幸运还是......

class X {
   public:
   static void proxy(int i) {}
}
makecontext(..., (void (*)(void)) X::proxy, ...);
Run Code Online (Sandbox Code Playgroud)

VS

extern "C" void proxy(int i) {}
makecontext(..., (void (*)(void)) proxy, ...);
Run Code Online (Sandbox Code Playgroud)

编辑:你能展示静态成员版本不起作用的编译器或架构(并且它不是编译器中的错误)吗?

Joh*_*itb 33

是的,你只是幸运:) extern"C"是C语言的一种语言链接,每个C++编译器都必须支持,除了默认的extern"C++".编译器可能支持其他语言链接.例如,GCC支持extern"Java",它允许与java代码接口(虽然这非常麻烦).

extern"C"告诉编译器你的函数可以被C代码调用.这可以但不是必须包括适当的调用约定和适当的C语言名称修改(有时称为"装饰")等,具体取决于实现.如果你有一个静态成员函数,它的调用约定是你的C++编译器之一.它们通常与该平台的C编译器相同 - 所以我说你很幸运.如果你有一个C API并且你传递了一个函数指针,那么最好总是把一个放到用extern"C"声明的函数中

extern "C" void foo() { ... }
Run Code Online (Sandbox Code Playgroud)

即使函数指针类型不包含链接规范,但看起来像

void(*)(void)
Run Code Online (Sandbox Code Playgroud)

链接是类型的组成部分 - 如果没有typedef,你就无法直接表达它:

extern "C" typedef void(*extern_c_funptr_t)();
Run Code Online (Sandbox Code Playgroud)

严格模式下的Comeau C++编译器将发出错误,例如,如果您尝试将上面的extern"C"函数的地址分配给a (void(*)()),因为这是指向具有C++链接的函数的指针.


dir*_*tly 5

注意,这extern C是C/C++互操作性的推荐方式.是主人谈论它.添加到eduffy的答案:请注意,不推荐使用全局命名空间中的静态函数和变量.至少使用匿名命名空间.

回到extern C:如果你不使用extern C,你必须知道确切的受损名称并使用它.这更令人痛苦.