22

静态成员函数和外部“C”链接函数有什么区别?例如,在 C++ 中使用“makecontext”时,我需要传递一个指向函数的指针。Google 建议使用外部“C”链接,因为“makecontext”是 C。但我发现使用静态也可以。我只是幸运还是...

class X {
   public:
   static void proxy(int i) {}
}
makecontext(..., (void (*)(void)) X::proxy, ...);

对比

extern "C" void proxy(int i) {}
makecontext(..., (void (*)(void)) proxy, ...);

编辑:您能否展示静态成员版本不起作用的编译器或体系结构(并且它不是编译器中的错误)?

4

5 回答 5

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" 函数的地址分配给 a (void(*)()),因为这是指向具有 C++ 链接的函数的指针。

于 2009-02-26T20:06:24.913 回答
5

请注意,这extern C是 C/C++ 互操作性的推荐方式。这里是大师讲的。添加到 eduffy 的答案:请注意,全局命名空间中的静态函数和变量已被弃用。至少使用匿名命名空间。

回到extern C:如果您不使用 extern C,您将必须知道确切的损坏名称并使用它。那更痛苦。

于 2009-02-26T20:07:09.263 回答
4

extern "C"禁用 C++ 编译器的名称修饰(重载所必需的)。

如果将 A.cpp 中的函数声明为static,则 B.cpp 无法找到它(它是 C 的剩余部分,它与将函数放入匿名命名空间中的效果相同)。

于 2009-02-26T20:02:33.597 回答
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指针,因此编译器可以自由地将它们视为非成员函数。同样,这里的行为是特定于平台的。

于 2009-02-26T20:26:24.817 回答
2

一般来说

存储类:

存储类用于指示变量或标识符的持续时间和范围。

期间:

持续时间表示变量的生命周期。

范围:

范围表示变量的可见性。

静态存储类:

静态存储类用于声明一个标识符,该标识符是函数或文件的局部变量,并且在控制从声明的位置传递后存在并保留其值。此存储类具有永久的持续时间。此类声明的变量在函数的一次调用到下一次调用中保留其值。范围是本地的。变量仅由它在其中声明的函数知道,或者如果在文件中全局声明,它仅由该文件中的函数知道或看到。这个存储类保证变量的声明也将变量初始化为零或所有位关闭。

外部存储类:

extern 存储类用于声明一个全局变量,该全局变量将被文件中的函数知道并且能够被程序中的所有函数知道。此存储类具有永久的持续时间。此类的任何变量都保留其值,直到被另一个赋值更改。范围是全球性的。程序中的所有函数都可以知道或看到变量。

于 2013-08-06T09:14:20.397 回答