extern "C" 声明如何工作?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2403391/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:23:06  来源:igfitidea点击:

How does an extern "C" declaration work?

c++cextern-c

提问by samoz

I'm taking a programming languages course and we're talking about the extern "C"declaration.

我正在学习编程语言课程,我们正在谈论extern "C"声明。

How does this declaration work at a deeper level other than "it interfaces C and C++"? How does this affect the bindings that take place in the program as well?

除了“它接口 C 和 C++”之外,这个声明如何在更深层次上工作?这如何影响程序中发生的绑定?

回答by Bertrand Marron

extern "C"is used to ensure that the symbols following are not mangled(decorated).

extern "C"用于确保后面的符号不被破坏(修饰)。



Example:

例子:

Let's say we have the following code in a file called test.cpp:

假设我们在名为 的文件中有以下代码test.cpp

extern "C" {
  int foo() {
    return 1;
  }
}

int bar() {
  return 1;
}

If you run gcc -c test.cpp -o test.o

如果你跑 gcc -c test.cpp -o test.o

Take a look at the symbols names:

看一下符号名称:

00000010 T _Z3barv

00000000 T foo

00000010 T _Z3barv

00000000吨富

foo()keeps its name.

foo()保留它的名字。

回答by Cthutu

Let's look at a typical function that can compile in both C and C++:

让我们看一个可以在 C 和 C++ 中编译的典型函数:

int Add (int a, int b)
{
    return a+b;
}

Now in C the function is called "_Add" internally. Whereas the C++ function is called something completely different internally using a system called name-mangling. Its basically a way to name a function so that the same function with different parameters has a different internal name.

现在在 C 中,该函数在内部称为“_Add”。而 C++ 函数在内部使用名为 name-mangling 的系统调用完全不同的东西。它基本上是一种命名函数的方法,以便具有不同参数的相同函数具有不同的内部名称。

So if Add() is defined in add.c, and you have the prototype in add.h you will get a problem if you try to include add.h in a C++ file. Because the C++ code is looking for a function with a name different to the one in add.c you will get a linker error. To get around that problem you must include add.c by this method:

因此,如果 Add() 在 add.c 中定义,并且原型在 add.h 中,如果您尝试将 add.h 包含在 C++ 文件中,则会出现问题。因为 C++ 代码正在寻找名称与 add.c 中的名称不同的函数,所以您将收到链接器错误。要解决该问题,您必须通过以下方法包含 add.c:

extern "C"
{
#include "add.h"
}

Now the C++ code will link with _Add instead of the C++ name mangled version.

现在 C++ 代码将与 _Add 链接,而不是 C++ 名称错位版本。

That's one of the uses of the expression. Bottom line, if you need to compile code that is strictly C in a C++ program (via an include statement or some other means) you need to wrap it with a extern "C" { ... } declaration.

这是表达式的用途之一。最重要的是,如果您需要在 C++ 程序中编译严格为 C 的代码(通过 include 语句或其他方式),则需要使用 extern "C" { ... } 声明对其进行包装。

回答by Reed Copsey

When you flag a block of code with extern "C", you're telling the system to use C style linkage.

当您使用 extern "C" 标记代码块时,您是在告诉系统使用 C 风格的链接。

This, mainly, affects the way the linker mangles the names. Instead of using C++ style name mangling (which is more complex to support operator overloads), you get the standard C-style naming out of the linker.

这主要影响链接器对名称的处理方式。您无需使用 C++ 风格的名称修饰(支持运算符重载更复杂),而是从链接器中获得标准的 C 风格命名。

回答by gilbertc

In C++ the name/symbol of the functions are actually renamed to something else such that different classes/namespaces can have functions of same signatures. In C, the functions are all globally defined and no such customized renaming process is needed.

在 C++ 中,函数的名称/符号实际上被重命名为其他东西,这样不同的类/命名空间可以具有相同签名的函数。在 C 中,函数都是全局定义的,不需要这种自定义的重命名过程。

To make C++ and C talk with each other, "extern C" instructs the compiler not to use the C convention.

为了使 C++ 和 C 相互通信,“extern C”指示编译器不要使用 C 约定。

回答by Johannes Schaub - litb

It should be noted that extern "C"also modifies the types of functions. It does not only modify things on lower levels:

需要注意的是,extern "C"还修改了函数的类型。它不仅会修改较低级别的内容:

extern "C" typedef void (*function_ptr_t)();

void foo();

int main() { function_ptr_t fptr = &foo; } // error!

The type of &foodoes not equal the type that the typedef designates (although the code is accepted by some, but not all compilers).

的类型&foo不等于 typedef 指定的类型(尽管该代码被某些编译器接受,但并非所有编译器都接受)。

回答by quamrana

extern C affects name mangling by the C++ compiler. Its a way of getting the C++ compiler to not mangle names, or rather to mangle them in the same way that a C compiler would. This is the way it interfaces C and C++.

extern C 影响 C++ 编译器的名称修改。它是一种让 C++ 编译器不修改名称的方法,或者更确切地说,以与 C 编译器相同的方式修改它们。这就是它接口 C 和 C++ 的方式。

As an example:

举个例子:

extern "C" void foo(int i);

will allow the function to be implemented in a C module, but allow it to be called from a C++ module.

将允许在 C 模块中实现该函数,但允许从 C++ 模块调用它。

The trouble comes when trying to get a C module to call a C++ function (obviously C can't use C++ classes) defined in a C++ module. The C compiler doesn't like extern "C".

当试图让 C 模块调用 C++ 模块中定义的 C++ 函数(显然 C 不能使用 C++ 类)时,麻烦就来了。C 编译器不喜欢extern "C".

So you need to use this:

所以你需要使用这个:

#ifdef __cplusplus
extern "C" {
#endif

void foo(int i);

#ifdef __cplusplus
}
#endif

Now when this appears in a header file, both the C and C++ compilers will be happy with the declaration and it could now be defined in either a C or C++ module, and can be called by both C and C++ code.

现在,当它出现在头文件中时,C 和 C++ 编译器都会对声明感到满意,现在它可以在 C 或 C++ 模块中定义,并且可以被 C 和 C++ 代码调用。

回答by Harvey

extern "C" denotes that the enclosed code uses C-style linking and name mangling. C++ uses a more complex name mangling format. Here's an example:

extern "C" 表示封闭的代码使用 C 风格的链接和名称修改。C++ 使用更复杂的名称修饰格式。下面是一个例子:

http://en.wikipedia.org/wiki/Name_mangling

http://en.wikipedia.org/wiki/Name_mangling

int example(int alpha, char beta);

in C: _example

在 C: _example

in C++: __Z7exampleic

在 C++ 中: __Z7exampleic

Update: As GManNickG notes in the comments, the pattern of name mangling is compiler dependent.

更新:正如 GManNickG 在评论中所指出的,名称修改的模式取决于编译器。

回答by Dongwei Wang

extern "C", is a keyword to declare a function with C bindings, because C compiler and C++ compiler will translate source into different form in object file:

extern "C", 是声明一个带有 C 绑定的函数的关键字,因为 C 编译器和 C++ 编译器会将源代码转换为目标文件中的不同形式:

For example, a code snippet is as follows:

例如,一段代码片段如下:

int _cdecl func1(void) {return 0}
int _stdcall func2(int) {return 0}
int _fastcall func3(void) {return 1}

32-bit C compilers will translate the code in the form as follows:

32 位 C 编译器将按如下形式翻译代码:

_func1
_func2@4
@func3@4

in the cdecl, func1 will translate as '_name'

在 cdecl 中,func1 将转换为“ _name

in the stdcall, func2 will translate as '_name@X'

在 stdcall 中, func2 将转换为 ' _name@X'

in the fastcall, func2 will translate as '@name@X'

在 fastcall 中,func2 将转换为“ @name@X

'X' means the how many bytes of the parameters in parameter list.

' X'表示参数列表中参数的字节数。

64-bit convention on Windows has no leading underscore

Windows 上的 64 位约定没有前导下划线

In C++, classes, templates, namespaces and operator overloading are introduced, since it is not allowed two functions with the same name, C++ compiler provide the type information in the symbol name,

C++中引入了类、模板、命名空间和运算符重载,由于不允许两个函数同名,C++编译器在符号名中提供了类型信息,

for example, a code snippet is as follows:

例如,一段代码片段如下:

int func(void) {return 1;}
int func(int) {return 0;}
int func_call(void) {int m=func(), n=func(0);}

C++ compiler will translate the code as follows:

C++编译器将代码翻译如下:

int func_v(void) {return 1;}
int func_i(int) {return 0;}
int func_call(void) {int m=_func_v(), n=_func_i(0);}

'_v' and '_i' are type information of 'void' and 'int'

'_v' 和 '_i' 是 'void' 和 'int' 的类型信息

回答by Joe Pitz

Here is a quote from msdn

这是来自 msdn 的引用

"The extern keyword declares a variable or function and specifies that it has external linkage (its name is visible from files other than the one in which it's defined). When modifying a variable, extern specifies that the variable has static duration (it is allocated when the program begins and deallocated when the program ends). The variable or function may be defined in another source file, or later in the same file. Declarations of variables and functions at file scope are external by default."

"extern 关键字声明一个变量或函数,并指定它具有外部链接(它的名称在定义它的文件之外的文件中可见)。修改变量时,extern 指定该变量具有静态持续时间(它被分配“当程序开始时并在程序结束时解除分配。变量或函数可能在另一个源文件中定义,或稍后在同一文件中定义。文件范围内的变量和函数声明默认是外部的。”

http://msdn.microsoft.com/en-us/library/0603949d%28VS.80%29.aspx

http://msdn.microsoft.com/en-us/library/0603949d%28VS.80%29.aspx