为什么我们需要 extern "C"{ #include <foo.h> } 在 C++ 中?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/67894/
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
Why do we need extern "C"{ #include <foo.h> } in C++?
提问by Landon
Why do we need to use:
为什么我们需要使用:
extern "C" {
#include <foo.h>
}
Specifically:
具体来说:
When should we use it?
What is happening at the compiler/linker level that requires us to use it?
How in terms of compilation/linking does this solve the problems which require us to use it?
我们应该什么时候使用它?
需要我们使用它的编译器/链接器级别发生了什么?
这在编译/链接方面如何解决需要我们使用它的问题?
采纳答案by duane
C and C++ are superficially similar, but each compiles into a very different set of code. When you include a header file with a C++ compiler, the compiler is expecting C++ code. If, however, it is a C header, then the compiler expects the data contained in the header file to be compiled to a certain format—the C++ 'ABI', or 'Application Binary Interface', so the linker chokes up. This is preferable to passing C++ data to a function expecting C data.
C 和 C++ 从表面上看很相似,但每个都编译成一组非常不同的代码。当您使用 C++ 编译器包含头文件时,编译器需要 C++ 代码。但是,如果它是 C 头文件,则编译器希望将头文件中包含的数据编译为某种格式 — C++“ABI”或“应用程序二进制接口”,因此链接器会阻塞。这比将 C++ 数据传递给需要 C 数据的函数更可取。
(To get into the really nitty-gritty, C++'s ABI generally 'mangles' the names of their functions/methods, so calling printf()
without flagging the prototype as a C function, the C++ will actually generate code calling _Zprintf
, plus extra crap at the end.)
(为了深入了解真正的细节,C++ 的 ABI 通常会“破坏”其函数/方法的名称,因此在调用时printf()
不将原型标记为 C 函数,C++ 实际上会生成代码调用_Zprintf
,最后加上额外的废话。 )
So: use extern "C" {...}
when including a c header—it's that simple. Otherwise, you'll have a mismatch in compiled code, and the linker will choke. For most headers, however, you won't even need the extern
because most system C headers will already account for the fact that they might be included by C++ code and already extern
their code.
所以:extern "C" {...}
在包含 ac 头时使用——就这么简单。否则,编译后的代码将不匹配,并且链接器将阻塞。但是,对于大多数头文件,您甚至不需要 ,extern
因为大多数系统 C 头文件已经考虑到它们可能包含在 C++ 代码中并且已经包含在extern
它们的代码中的事实。
回答by Todd Gamblin
extern "C" determines how symbols in the generated object file should be named. If a function is declared without extern "C", the symbol name in the object file will use C++ name mangling. Here's an example.
extern "C" 确定生成的目标文件中的符号应如何命名。如果在没有 extern "C" 的情况下声明函数,则目标文件中的符号名称将使用 C++ 名称修饰。这是一个例子。
Given test.C like so:
鉴于 test.C 像这样:
void foo() { }
Compiling and listing symbols in the object file gives:
编译和列出目标文件中的符号给出:
$ g++ -c test.C
$ nm test.o
0000000000000000 T _Z3foov
U __gxx_personality_v0
The foo function is actually called "_Z3foov". This string contains type information for the return type and parameters, among other things. If you instead write test.C like this:
foo 函数实际上被称为“_Z3foov”。该字符串包含返回类型和参数等的类型信息。如果您改为这样编写 test.C:
extern "C" {
void foo() { }
}
Then compile and look at symbols:
然后编译并查看符号:
$ g++ -c test.C
$ nm test.o
U __gxx_personality_v0
0000000000000000 T foo
You get C linkage. The name of the "foo" function in the object file is just "foo", and it doesn't have all the fancy type info that comes from name mangling.
你得到 C 链接。目标文件中“foo”函数的名称只是“foo”,它没有来自名称修改的所有花哨类型信息。
You generally include a header within extern "C" {} if the code that goes with it was compiled with a C compiler but you're trying to call it from C++. When you do this, you're telling the compiler that all the declarations in the header will use C linkage. When you link your code, your .o files will contain references to "foo", not "_Z3fooblah", which hopefully matches whatever is in the library you're linking against.
如果随附的代码是用 C 编译器编译的,但您试图从 C++ 调用它,则通常在 extern "C" {} 中包含一个标头。当你这样做时,你告诉编译器头文件中的所有声明都将使用 C 链接。当你链接你的代码时,你的 .o 文件将包含对“foo”的引用,而不是“_Z3fooblah”,它希望与你链接的库中的任何内容相匹配。
Most modern libraries will put guards around such headers so that symbols are declared with the right linkage. e.g. in a lot of the standard headers you'll find:
大多数现代库都会在这些头文件周围放置保护措施,以便使用正确的链接声明符号。例如,在许多标准标题中,您会发现:
#ifdef __cplusplus
extern "C" {
#endif
... declarations ...
#ifdef __cplusplus
}
#endif
This makes sure that when C++ code includes the header, the symbols in your object file match what's in the C library. You should only have to put extern "C" {} around your C header if it's old and doesn't have these guards already.
这可确保当 C++ 代码包含标头时,目标文件中的符号与 C 库中的符号相匹配。如果你的 C 头文件很旧并且没有这些守卫,你应该只需要在你的 C 头文件周围放置 extern "C" {} 。
回答by Trent
In C++, you can have different entities that share a name. For example here is a list of functions all named foo:
在 C++ 中,您可以拥有共享名称的不同实体。例如,这里是一个名为foo的函数列表:
A::foo()
B::foo()
C::foo(int)
C::foo(std::string)
A::foo()
B::foo()
C::foo(int)
C::foo(std::string)
In order to differentiate between them all, the C++ compiler will create unique names for each in a process called name-mangling or decorating. C compilers do not do this. Furthermore, each C++ compiler may do this is a different way.
为了区分它们,C++ 编译器将在称为名称修改或装饰的过程中为每个名称创建唯一的名称。C 编译器不会这样做。此外,每个 C++ 编译器可能以不同的方式执行此操作。
extern "C" tells the C++ compiler not to perform any name-mangling on the code within the braces. This allows you to call C functions from within C++.
extern "C" 告诉 C++ 编译器不要对大括号内的代码执行任何名称修改。这允许您从 C++ 中调用 C 函数。
回答by 1800 INFORMATION
It has to do with the way the different compilers perform name-mangling. A C++ compiler will mangle the name of a symbol exported from the header file in a completely different way than a C compiler would, so when you try to link, you would get a linker error saying there were missing symbols.
它与不同编译器执行名称修改的方式有关。C++ 编译器会以与 C 编译器完全不同的方式修改从头文件导出的符号的名称,因此当您尝试链接时,您会收到链接器错误,指出缺少符号。
To resolve this, we tell the C++ compiler to run in "C" mode, so it performs name mangling in the same way the C compiler would. Having done so, the linker errors are fixed.
为了解决这个问题,我们告诉 C++ 编译器以“C”模式运行,因此它以与 C 编译器相同的方式执行名称修改。这样做后,链接器错误被修复。
回答by tialaramex
C and C++ have different rules about names of symbols. Symbols are how the linker knows that the call to function "openBankAccount" in one object file produced by the compiler is a reference to that function you called "openBankAccount" in another object file produced from a different source file by the same (or compatible) compiler. This allows you to make a program out of more than one source file, which is a relief when working on a large project.
C 和 C++ 对符号名称有不同的规则。符号是链接器如何知道编译器生成的一个目标文件中对函数“openBankAccount”的调用是对您在另一个目标文件中调用的函数“openBankAccount”的引用,该函数由相同的(或兼容的)从不同的源文件生成编译器。这允许您使用多个源文件制作程序,这在处理大型项目时是一种解脱。
In C the rule is very simple, symbols are all in a single name space anyway. So the integer "socks" is stored as "socks" and the function count_socks is stored as "count_socks".
在 C 中,规则非常简单,无论如何,符号都在一个名称空间中。所以整数“socks”存储为“socks”,函数count_socks存储为“count_socks”。
Linkers were built for C and other languages like C with this simple symbol naming rule. So symbols in the linker are just simple strings.
链接器是用这个简单的符号命名规则为 C 和其他语言(如 C)构建的。所以链接器中的符号只是简单的字符串。
But in C++ the language lets you have namespaces, and polymorphism and various other things that conflict with such a simple rule. All six of your polymorphic functions called "add" need to have different symbols, or the wrong one will be used by other object files. This is done by "mangling" (that's a technical term) the names of symbols.
但是在 C++ 中,该语言允许您拥有命名空间、多态性以及与这种简单规则相冲突的各种其他事物。称为“add”的所有六个多态函数都需要具有不同的符号,否则其他目标文件将使用错误的符号。这是通过“修改”(这是一个技术术语)符号的名称来完成的。
When linking C++ code to C libraries or code, you need extern "C" anything written in C, such as header files for the C libraries, to tell your C++ compiler that these symbol names aren't to be mangled, while the rest of your C++ code of course must be mangled or it won't work.
将 C++ 代码链接到 C 库或代码时,您需要 extern "C" 用 C 编写的任何内容,例如 C 库的头文件,以告诉您的 C++ 编译器这些符号名称不会被修改,而其余的您的 C++ 代码当然必须被破坏,否则它将无法工作。
回答by Tony M
When should we use it?
我们应该什么时候使用它?
When you are linking C libaries into C++ object files
当您将 C 库链接到 C++ 对象文件时
What is happening at the compiler/linker level that requires us to use it?
需要我们使用它的编译器/链接器级别发生了什么?
C and C++ use different schemes for symbol naming. This tells the linker to use C's scheme when linking in the given library.
C 和 C++ 使用不同的符号命名方案。这告诉链接器在给定库中链接时使用 C 的方案。
How in terms of compilation/linking does this solve the problems which require us to use it?
这在编译/链接方面如何解决需要我们使用它的问题?
Using the C naming scheme allows you to reference C-style symbols. Otherwise the linker would try C++-style symbols which wouldn't work.
使用 C 命名方案允许您引用 C 风格的符号。否则链接器会尝试 C++ 风格的符号,但这些符号不起作用。
回答by HitScan
You should use extern "C" anytime that you include a header defining functions residing in a file compiled by a C compiler, used in a C++ file. (Many standard C libraries may include this check in their headers to make it simpler for the developer)
在包含定义函数的头文件的任何时候都应该使用 extern "C",这些函数位于由 C 编译器编译的文件中,用于 C++ 文件。(许多标准 C 库可能会在其头文件中包含此检查,以使开发人员更简单)
For example, if you have a project with 3 files, util.c, util.h, and main.cpp and both the .c and .cpp files are compiled with the C++ compiler (g++, cc, etc) then it isn't really needed, and may even cause linker errors. If your build process uses a regular C compiler for util.c, then you will need to use extern "C" when including util.h.
例如,如果您有一个包含 3 个文件、util.c、util.h 和 main.cpp 的项目,并且 .c 和 .cpp 文件都是使用 C++ 编译器(g++、cc 等)编译的,那么它不是t 真的需要,甚至可能导致链接器错误。如果您的构建过程对 util.c 使用常规 C 编译器,那么在包含 util.h 时您将需要使用 extern "C"。
What is happening is that C++ encodes the parameters of the function in its name. This is how function overloading works. All that tends to happen to a C function is the addition of an underscore ("_") to the beginning of the name. Without using extern "C" the linker will be looking for a function named DoSomething@@int@float() when the function's actual name is _DoSomething() or just DoSomething().
发生的事情是 C++ 在其名称中对函数的参数进行编码。这就是函数重载的工作原理。C 函数通常会在名称的开头添加下划线(“_”)。如果不使用 extern "C",当函数的实际名称是 _DoSomething() 或只是 DoSomething() 时,链接器将查找名为 DoSomething@@int@float() 的函数。
Using extern "C" solves the above problem by telling the C++ compiler that it should look for a function that follows the C naming convention instead of the C++ one.
使用 extern "C" 通过告诉 C++ 编译器它应该查找遵循 C 命名约定而不是 C++ 命名约定的函数来解决上述问题。
回答by mbyrne215
The C++ compiler creates symbol names differently than the C compiler. So, if you are trying to make a call to a function that resides in a C file, compiled as C code, you need to tell the C++ compiler that the symbol names that it is trying to resolve look different than it defaults to; otherwise the link step will fail.
C++ 编译器创建符号名称的方式与 C 编译器不同。因此,如果您尝试调用驻留在 C 文件中并编译为 C 代码的函数,您需要告诉 C++ 编译器它试图解析的符号名称与默认值不同;否则链接步骤将失败。
回答by Paul Lalonde
The extern "C" {}
construct instructs the compiler not to perform mangling on names declared within the braces. Normally, the C++ compiler "enhances" function names so that they encode type information about arguments and the return value; this is called the mangled name. The extern "C"
construct prevents the mangling.
该extern "C" {}
构造指示编译器不要对大括号内声明的名称执行重整。通常,C++ 编译器会“增强”函数名称,以便它们对有关参数和返回值的类型信息进行编码;这就是所谓的错位名称。该extern "C"
构造可防止重整。
It is typically used when C++ code needs to call a C-language library. It may also be used when exposing a C++ function (from a DLL, for example) to C clients.
它通常在 C++ 代码需要调用 C 语言库时使用。它也可用于向 C 客户端公开 C++ 函数(例如,来自 DLL)。
回答by Eric Z Beard
This is used to resolve name mangling issues. extern C means that the functions are in a "flat" C-style API.
这用于解决名称修改问题。extern C 意味着这些函数在一个“扁平”的 C 风格的 API 中。