静态与外部“C”/“C++”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/592160/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
static vs extern "C"/"C++"
提问by Giovanni Funchal
What is the difference between a static member function and an extern "C" linkage function ? For instance, when using "makecontext" in C++, I need to pass a pointer to function. Google recommends using extern "C" linkage for it, because "makecontext" is C. But I found out that using static works as well. Am I just lucky or...
静态成员函数和外部“C”链接函数有什么区别?例如,在 C++ 中使用“makecontext”时,我需要传递一个指向函数的指针。Google 建议使用 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, ...);
EDIT: Can you show a compiler or architecture where the static member version does not work (and it's not a bug in the compiler) ?
编辑:您能否展示静态成员版本不起作用的编译器或体系结构(并且它不是编译器中的错误)?
回答by Johannes Schaub - litb
Yes, you are just lucky :) The extern "C" is one language linkage for the C language that every C++ compiler has to support, beside extern "C++" which is the default. Compilers may supports other language linkages. GCC for example supports extern "Java" which allows interfacing with java code (though that's quite cumbersome).
是的,你很幸运:) extern "C" 是每个 C++ 编译器都必须支持的 C 语言的一种语言链接,除了默认的 extern "C++"。编译器可能支持其他语言链接。例如,GCC 支持 extern "Java",它允许与 Java 代码交互(尽管这很麻烦)。
extern "C" tells the compiler that your function is callable by C code. That can, but not must, include the appropriate calling convention and the appropriate C language name mangling (sometimes called "decoration") among other things depending on the implementation. If you have a static member function, the calling convention for it is the one of your C++ compiler. Often they are the same as for the C compiler of that platform - so i said you are just lucky. If you have a C API and you pass a function pointer, better always put one to a function declared with extern "C" like
extern "C" 告诉编译器你的函数可以被 C 代码调用。这可以(但不是必须)包括适当的调用约定和适当的 C 语言名称修改(有时称为“装饰”)等,具体取决于实现。如果你有一个静态成员函数,它的调用约定是你的 C++ 编译器之一。通常它们与该平台的 C 编译器相同 - 所以我说你很幸运。如果你有一个 C API 并且你传递了一个函数指针,最好总是把它放在一个用 extern "C" 声明的函数中,比如
extern "C" void foo() { ... }
Even though the function pointer type does not contain the linkage specification but rather looks like
即使函数指针类型不包含链接规范,而是看起来像
void(*)(void)
The linkage is an integral part of the type - you just can't express it directly without a typedef:
链接是类型的一个组成部分——如果没有 typedef,你就不能直接表达它:
extern "C" typedef void(*extern_c_funptr_t)();
The Comeau C++ compiler, in strict mode, will emit an error for example if you try to assign the address of the extern "C" function of above to a (void(*)())
, beause this is a pointer to a function with C++ linkage.
Comeau C++ 编译器在严格模式下会发出错误,例如,如果您尝试将上面的 extern "C" 函数的地址分配给 a (void(*)())
,因为这是指向具有 C++ 链接的函数的指针。
回答by dirkgently
Note, that extern C
is the recommendedway of C/C++ interoperability. Hereis the master talking about it. To add to eduffy's answer: note that static functions and variables in the global namespace are deprecated. Use an anonymous namespace at least.
请注意,这extern C
是C/C++ 互操作性的推荐方式。这里是大师讲的。添加到 eduffy 的答案:请注意,不推荐使用全局命名空间中的静态函数和变量。至少使用匿名命名空间。
Back to extern C
: if you don't use extern C you will have to know the exact mangled name and use it. That is much more of a pain.
回到extern C
:如果您不使用 extern C,您将必须知道确切的损坏名称并使用它。那更是一种痛苦。
回答by eduffy
extern "C"
disables the C++ compiler's name mangling (which is required for overloading).
extern "C"
禁用 C++ 编译器的名称修改(重载所需)。
If you declare a function in A.cpp to be static
, then it cannot be found by B.cpp (it's leftover from C, and it has the same effect of putting a function inside an anonymous namespace).
如果您将 A.cpp 中的函数声明为static
,则B.cpp无法找到它(它是 C 遗留下来的,与将函数放入匿名命名空间的效果相同)。
回答by Andrew Khosravian
Most of what extern "C"
does is largely compiler dependant. Many platforms change the name mangling and calling convention based off the declaration, but none of that is specified by the standard. Really the only thing the standard requires is that the code in the block is callable from C functions. As for your specific question, the standard says:
大部分extern "C"
功能在很大程度上取决于编译器。许多平台根据声明更改名称修改和调用约定,但标准中没有指定这些。实际上,标准唯一要求的是块中的代码可以从 C 函数中调用。至于你的具体问题,标准说:
Two function types with different language linkages are distinct types even if they are otherwise identical.
具有不同语言链接的两个函数类型是不同的类型,即使它们在其他方面是相同的。
This means extern "C" void proxy(int i) {}
and /*extern "C++"*/void proxy(int i) {}
have different types, and as a result pointers to these functions would have different types as well. The compiler doesn't fail your code for the same reason it wouldn't fail a great piece of work like:
这意味着extern "C" void proxy(int i) {}
并且/*extern "C++"*/void proxy(int i) {}
具有不同的类型,因此指向这些函数的指针也将具有不同的类型。编译器不会因为相同的原因而使您的代码失败,它不会使诸如以下的伟大工作失败:
int *foo = (int*)50;
makecontext(..., (void (*)(void)) foo, ...);
This code might work on some platform, but that doesn't mean it will work on another platform (even if the compiler was fully standard compliant). You are taking advantage of how your particular platform works, which might be ok if you aren't concerned about writing portable code.
这段代码可能在某些平台上工作,但这并不意味着它可以在另一个平台上工作(即使编译器完全符合标准)。您正在利用您的特定平台的工作方式,如果您不关心编写可移植代码,这可能没问题。
As for static member functions, they aren't required to have a this
pointer so the compiler is free to treat them as a non member function. Again, the behavior here is platform specific.
至于静态成员函数,它们不需要有this
指针,因此编译器可以自由地将它们视为非成员函数。同样,这里的行为是特定于平台的。
回答by Durai Amuthan.H
Generally speaking
通常来说,一般来说
Storage classes:
存储类:
storage classes are used to indicate duration and scope of a variable or identifier.
存储类用于指示变量或标识符的持续时间和范围。
Duration:
期间:
Duration indicates the life span of a variable.
持续时间表示变量的生命周期。
Scope:
范围:
Scope indicates the visibility of the variable.
范围指示变量的可见性。
Static storage class:
静态存储类:
The static storage class is used to declare an identifier that is a local variable either to a function or a file and that exists and retains its value after control passes from where it was declared. This storage class has a duration that is permanent. A variable declared of this class retains its value from one call of the function to the next. The scope is local. A variable is known only by the function it is declared within or if declared globally in a file, it is known or seen only by the functions within that file. This storage class guarantees that declaration of the variable also initializes the variable to zero or all bits off.
静态存储类用于声明一个标识符,该标识符是函数或文件的局部变量,并且在控制权从声明的位置传递后存在并保留其值。此存储类具有永久的持续时间。此类声明的变量从函数的一次调用到下一次调用都保留其值。范围是本地的。变量只能由它在其中声明的函数知道,或者如果在文件中全局声明,则只能由该文件中的函数知道或看到。这个存储类保证变量的声明也将变量初始化为零或所有位关闭。
Extern storage class:
外部存储类:
The extern storage class is used to declare a global variable that will be known to the functions in a file and capable of being known to all functions in a program. This storage class has a duration that is permanent. Any variable of this class retains its value until changed by another assignment. The scope is global. A variable can be known or seen by all functions within a program.
extern 存储类用于声明一个全局变量,该变量将为文件中的函数所知,并且能够为程序中的所有函数所知。此存储类具有永久的持续时间。此类的任何变量都保留其值,直到被另一个赋值更改。范围是全球性的。程序中的所有函数都可以知道或看到变量。