static vs extern“C”/“C ++”

问题描述 投票:22回答:5

静态成员函数和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, ...);

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

c++ function-pointers static-members linkage extern-c
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”函数的地址分配给(void(*)()),因为这是指向具有C ++链接的函数的指针。


5
投票

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

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


4
投票

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

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


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指针,因此编译器可以将它们视为非成员函数。同样,这里的行为是特定于平台的。


2
投票

一般来说

存储类:

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

持续时间:

持续时间表示变量的寿命。

范围:

范围表示变量的可见性。

静态存储类:

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

外部存储类:

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

© www.soinside.com 2019 - 2024. All rights reserved.