静态成员函数和extern“C”链接函数有什么区别?例如,在C ++中使用“makecontext”时,我需要传递一个指向函数的指针。谷歌建议使用extern“C”链接,因为“makecontext”是C.但我发现使用静态也是如此。我只是幸运还是......
class X {
public:
static void proxy(int i) {}
}
makecontext(..., (void (*)(void)) X::proxy, ...);
VS
extern "C" void proxy(int i) {}
makecontext(..., (void (*)(void)) proxy, ...);
编辑:你能展示静态成员版本不起作用的编译器或架构(这不是编译器中的错误)吗?
答案 0 :(得分: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() { ... }
即使函数指针类型不包含链接规范,但看起来像
void(*)(void)
链接是类型的组成部分 - 如果没有typedef,你就无法直接表达它:
extern "C" typedef void(*extern_c_funptr_t)();
Comeau C ++编译器在严格模式下会发出错误,例如,如果您尝试将上面的extern“C”函数的地址分配给(void(*)())
,因为这是一个指向函数的指针与C ++联系。
答案 1 :(得分:5)
请注意,extern C
是C / C ++互操作性的推荐方式。 Here是主人谈论它。添加到eduffy的答案:请注意,不推荐使用全局命名空间中的静态函数和变量。至少使用匿名命名空间。
返回extern C
:如果您不使用extern C,您将必须知道确切的受损名称并使用它。这更令人痛苦。
答案 2 :(得分:4)
extern "C"
禁用C ++编译器的名称修改(重载所需)。
如果你将A.cpp中的一个函数声明为static
,那么B.cpp就找不到它(它是C的剩余部分,它与将函数放入匿名命名空间的效果相同)
答案 3 :(得分:2)
extern "C"
所做的大部分内容主要取决于编译器。许多平台根据声明更改名称修改和调用约定,但标准没有指定。真正唯一标准要求的是块中的代码可以从C函数调用。至于你的具体问题,标准说:
两种不同的功能类型 语言联系是不同的类型 即使他们是相同的。
这意味着extern "C" void proxy(int i) {}
和/*extern "C++"*/void proxy(int i) {}
具有不同的类型,因此指向这些函数的指针也会有不同的类型。编译器不会使代码失败的原因与以下原因相同:
int *foo = (int*)50;
makecontext(..., (void (*)(void)) foo, ...);
此代码可能在某个平台上有效,但这并不意味着它可以在另一个平台上运行(即使编译器完全符合标准)。您正在利用您的特定平台的工作方式,如果您不关心编写可移植代码,这可能没问题。
对于静态成员函数,它们不需要具有this
指针,因此编译器可以将它们视为非成员函数。同样,这里的行为是特定于平台的。
答案 4 :(得分:2)
一般来说
存储类:
存储类用于指示变量或标识符的持续时间和范围。
<强>持续时间:强>
持续时间表示变量的生命周期。
<强>范围:强>
范围表示变量的可见性。
静态存储类:
静态存储类用于声明一个标识符,该标识符是函数或文件的局部变量,并且存在并在控制从声明它的位置传递之后保留其值。此存储类的持续时间是永久性的。声明此类的变量将保留其从函数的一次调用到下一次的值。范围是本地的。变量只能通过声明的函数知道,或者如果在文件中全局声明,则只有该文件中的函数才知道或看到它。此存储类保证变量的声明也将变量初始化为零或关闭所有位。
外部存储类:
extern存储类用于声明一个全局变量,该变量将为文件中的函数所知,并且能够为程序中的所有函数所知。此存储类的持续时间是永久性的。此类的任何变量都保留其值,直到另一个赋值更改为止。范围是全球性的。程序中的所有函数都可以知道或看到变量。