C++中extern“C”的作用是什么?

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

What is the effect of extern "C" in C++?

c++clinkagename-manglingextern-c

提问by Litherum

What exactly does putting extern "C"into C++ code do?

extern "C"放入 C++ 代码到底有什么作用?

For example:

例如:

extern "C" {
   void foo();
}

采纳答案by Faisal Vali

extern "C" makes a function-name in C++ have 'C' linkage (compiler does not mangle the name) so that client C code can link to (i.e use) your function using a 'C' compatible header file that contains just the declaration of your function. Your function definition is contained in a binary format (that was compiled by your C++ compiler) that the client 'C' linker will then link to using the 'C' name.

extern "C" 使 C++ 中的函数名称具有 'C' 链接(编译器不会破坏名称),以便客户端 C 代码可以使用仅包含你的函数的声明。您的函数定义包含在二进制格式中(由您的 C++ 编译器编译),然后客户端“C”链接器将使用“C”名称链接到该格式。

Since C++ has overloading of function names and C does not, the C++ compiler cannot just use the function name as a unique id to link to, so it mangles the name by adding information about the arguments. A C compiler does not need to mangle the name since you can not overload function names in C. When you state that a function has extern "C" linkage in C++, the C++ compiler does not add argument/parameter type information to the name used for linkage.

由于 C++ 有函数名的重载而 C 没有,C++ 编译器不能只使用函数名作为唯一的 id 来链接,所以它通过添加有关参数的信息来破坏名称。AC 编译器不需要修改名称,因为您不能在 C 中重载函数名称。当您在 C++ 中声明一个函数具有 extern "C" 链接时,C++ 编译器不会将参数/参数类型信息添加到用于的名称中连锁。

Just so you know, you can specify "C" linkage to each individual declaration/definition explicitly or use a block to group a sequence of declarations/definitions to have a certain linkage:

正如您所知,您可以明确地为每个单独的声明/定义指定“C”链接,或者使用块将一系列声明/定义分组以具有特定链接:

extern "C" void foo(int);
extern "C"
{
   void g(char);
   int i;
}

If you care about the technicalities, they are listed in section 7.5 of the C++03 standard, here is a brief summary (with emphasis on extern "C"):

如果你关心技术细节,它们列在 C++03 标准的第 7.5 节中,这里是一个简短的总结(重点是 extern "C"):

  • extern "C" is a linkage-specification
  • Every compiler is requiredto provide "C" linkage
  • a linkage specification shall occur only in namespace scope
  • all function types, function names and variable names have a language linkage See Richard's Comment:Only function names and variable names with external linkage have a language linkage
  • two function types with distinct language linkages are distinct types even if otherwise identical
  • linkage specs nest, inner one determines the final linkage
  • extern "C" is ignored for class members
  • at most one function with a particular name can have "C" linkage (regardless of namespace)
  • extern "C" forces a function to have external linkage (cannot make it static) See Richard's comment:'static' inside 'extern "C"' is valid; an entity so declared has internal linkage, and so does not have a language linkage
  • Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages is implementation-defined and language-dependent. Only where the object layout strategies of two language implementations are similar enough can such linkage be achieved
  • extern "C" 是一个链接规范
  • 每个编译器都需要提供“C”链接
  • 链接规范应仅出现在命名空间范围内
  • 所有函数类型、函数名和变量名都有语言链接参见Richard的评论:只有具有外部链接的函数名和变量名才有语言链接
  • 具有不同语言链接的两个函数类型是不同的类型,即使在其他方面相同
  • 联动规格巢,内部决定最终联动
  • 类成员忽略 extern "C"
  • 最多一个具有特定名称的函数可以具有“C”链接(无论命名空间如何)
  • extern "C" 强制函数具有外部链接(不能使其成为静态)参见 Richard 的评论:'extern "C"' 内的 'static' 是有效的;如此声明的实体具有内部链接,因此没有语言链接
  • 从 C++ 到用其他语言定义的对象以及从其他语言到用 C++ 定义的对象的链接是实现定义的和语言相关的。只有两种语言实现的对象布局策略足够相似,才能实现这种联动

回答by UncaAlby

Just wanted to add a bit of info, since I haven't seen it posted yet.

只是想添加一些信息,因为我还没有看到它发布。

You'll very often see code in C headers like so:

你会经常在 C 头文件中看到这样的代码:

#ifdef __cplusplus
extern "C" {
#endif

// all of your legacy C code here

#ifdef __cplusplus
}
#endif

What this accomplishes is that it allows you to use that C header file with your C++ code, because the macro "__cplusplus" will be defined. But you can alsostill use it with your legacy C code, where the macro is NOTdefined, so it won't see the uniquely C++ construct.

这样做的目的是它允许您在 C++ 代码中使用该 C 头文件,因为将定义宏“__cplusplus”。但是你可以仍然使用旧的C代码,其中宏使用NOT定义,所以它不会看到独特的C ++结构。

Although, I have also seen C++ code such as:

虽然,我也见过 C++ 代码,例如:

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

which I imagine accomplishes much the same thing.

我想象它完成了同样的事情。

Not sure which way is better, but I have seen both.

不知道哪种方式更好,但我都见过。

回答by sud03r

In every C++ program, all non-static functions are represented in the binary file as symbols. These symbols are special text strings that uniquely identify a function in the program.

在每个 C++ 程序中,所有非静态函数在二进制文件中都表示为符号。这些符号是特殊的文本字符串,用于唯一标识程序中的函数。

In C, the symbol name is the same as the function name. This is possible because in C no two non-static functions can have the same name.

在 C 中,符号名称与函数名称相同。这是可能的,因为在 C 中没有两个非静态函数可以具有相同的名称。

Because C++ allows overloading and has many features that C does not — like classes, member functions, exception specifications - it is not possible to simply use the function name as the symbol name. To solve that, C++ uses so-called name mangling, which transforms the function name and all the necessary information (like the number and size of the arguments) into some weird-looking string processed only by the compiler and linker.

因为 C++ 允许重载并且有许多 C 没有的特性——比如类、成员函数、异常规范——不可能简单地使用函数名作为符号名。为了解决这个问题,C++ 使用了所谓的名称修饰,它将函数名称和所有必要的信息(如参数的数量和大小)转换为一些仅由编译器和链接器处理的看起来很奇怪的字符串。

So if you specify a function to be extern C, the compiler doesn't performs name mangling with it and it can be directly accessed using its symbol name as the function name.

因此,如果您将函数指定为 extern C,编译器不会对其进行名称修改,并且可以使用其符号名称作为函数名称直接访问它。

This comes handy while using dlsym()and dlopen()for calling such functions.

这在使用dlsym()dlopen()调用这些函数时很方便。

回答by tfmontague

C++ mangles function names to create an object-oriented language from a procedural language

C++ 修改函数名称以从过程语言创建面向对象的语言

Most programming languages aren't built on-top of existing programming languages. C++ is built on-top of C, and furthermore it's an object-oriented programming language built from a procedural programming language, and for that reason there are C++ expressions like extern "C"which provide backwards compatibility with C.

大多数编程语言都不是建立在现有编程语言之上的。C++ 建立在 C 之上,而且它是一种从过程编程语言构建的面向对象的编程语言,因此有 C+​​+ 表达式,例如extern "C"提供与 C 的向后兼容性。

Let's look at the following example:

让我们看看下面的例子:

#include <stdio.h>

// Two functions are defined with the same name
// but have different parameters

void printMe(int a) {
  printf("int: %i\n", a);
}

void printMe(char a) {
  printf("char: %c\n", a);
}

int main() {
  printMe("a");
  printMe(1);
  return 0;
}

A C compiler will not compile the above example, because the same function printMeis defined twice (even though they have different parameters int avs char a).

AC 编译器不会编译上面的例子,因为同一个函数printMe被定义了两次(即使它们有不同的参数int avs char a)。

gcc -o printMe printMe.c && ./printMe;
1 error. PrintMe is defined more than once.

gcc -o printMe printMe.c && ./printMe;
1 错误。PrintMe 被定义了不止一次。

A C++ compiler will compile the above example. It does not care that printMeis defined twice.

C++ 编译器将编译上述示例。它不在乎printMe定义两次。

g++ -o printMe printMe.c && ./printMe;

g++ -o printMe printMe.c && ./printMe;

This is because a C++ compiler implicitly renames (mangles) functions based on their parameters. In C, this feature was not supported. However, when C++ was built over C, the language was designed to be object-oriented, and needed to support the ability to create different classes with methods (functions) of the same name, and to override methods (method overriding) based on different parameters.

这是因为 C++ 编译器会根据函数的参数隐式重命名 ( mangles) 函数。在 C 中,不支持此功能。但是,当 C++ 基于 C 构建时,该语言被设计为面向对象的,并且需要支持使用相同名称的方法(函数)创建不同类的能力,以及基于不同的方法覆盖方法(方法覆盖)的能力。参数。

extern "C"says "don't mangle C function names"

extern "C"说“不要破坏 C 函数名称”

However, imagine we have a legacy C file named "parent.c" that includes function names from other legacy C files, "parent.h", "child.h", etc. If the legacy "parent.c" file is run through a C++ compiler, then the function names will be mangled, and they will no longer match the function names specified in "parent.h", "child.h", etc - so the function names in those external files would also need to be mangled. Mangling function names across a complex C program, those with lots of dependencies, can lead to broken code; so it might be convenient to provide a keyword which can tell the C++ compiler not to mangle a function name.

但是,假设我们有一个名为“parent.c”include的遗留 C 文件,它是来自其他遗留 C 文件的函数名称,“parent.h”、“child.h”等。如果遗留“parent.c”文件运行通过 C++ 编译器,然后函数名称将被修改,它们将不再与“parent.h”、“child.h”等中指定的函数名称匹配 - 因此这些外部文件中的函数名称也需要被破坏。在具有大量依赖项的复杂 C 程序中修改函数名称可能会导致代码损坏;所以提供一个关键字来告诉 C++ 编译器不要修改函数名可能会很方便。

The extern "C"keyword tells a C++ compiler not to mangle (rename) C function names.

extern "C"关键字告诉 C++ 编译器不要修改(重命名)C 函数名称。

For example:

例如:

extern "C" void printMe(int a);

extern "C" void printMe(int a);

回答by Sander Mertens

Not any C-header can be made compatible with C++ by merely wrapping in extern "C". When identifiers in a C-header conflict with C++ keywords the C++ compiler will complain about this.

仅通过包装在 extern "C" 中,不能使任何 C 头文件与 C++ 兼容。当 C 头文件中的标识符与 C++ 关键字冲突时,C++ 编译器会抱怨这一点。

For example, I have seen the following code fail in a g++ :

例如,我看到以下代码在 g++ 中失败:

extern "C" {
struct method {
    int virtual;
};
}

Kinda makes sense, but is something to keep in mind when porting C-code to C++.

有点道理,但在将 C 代码移植到 C++ 时要记住这一点。

回答by Employed Russian

It changes the linkage of a function in such a way that the function is callable from C. In practice that means that the function name is not mangled.

它以一种可从 C 调用函数的方式更改函数的链接。实际上,这意味着函数名称不会被破坏

回答by Mark Rushakoff

It informs the C++ compiler to look up the names of those functions in a C-style when linking, because the names of functions compiled in C and C++ are different during the linking stage.

它通知 C++ 编译器在链接时以 C 样式查找这些函数的名称,因为在链接阶段用 C 和 C++ 编译的函数名称是不同的。

回答by Flami

extern "C" is meant to be recognized by a C++ compiler and to notify the compiler that the noted function is (or to be) compiled in C style. So that while linking, it link to the correct version of function from C.

extern "C" 意在被 C++ 编译器识别,并通知编译器注意到的函数是(或将要)以 C 风格编译的。这样在链接时,它会从 C 链接到正确版本的函数。

回答by SturmCoder

I used 'extern "C"' before for dll(dynamic link library) files to make etc. main() function "exportable" so it can be used later in another executable from dll. Maybe an example of where I used to use it can be useful.

我之前对 dll(动态链接库)文件使用了“extern“C”,使等 main() 函数“可导出”,以便以后可以在另一个来自 dll 的可执行文件中使用它。也许我曾经使用它的一个例子可能很有用。

DLL

动态链接库

#include <string.h>
#include <windows.h>

using namespace std;

#define DLL extern "C" __declspec(dllexport)
//I defined DLL for dllexport function
DLL main ()
{
    MessageBox(NULL,"Hi from DLL","DLL",MB_OK);
}

EXE

可执行程序

#include <string.h>
#include <windows.h>

using namespace std;

typedef LPVOID (WINAPI*Function)();//make a placeholder for function from dll
Function mainDLLFunc;//make a variable for function placeholder

int main()
{
    char winDir[MAX_PATH];//will hold path of above dll
    GetCurrentDirectory(sizeof(winDir),winDir);//dll is in same dir as exe
    strcat(winDir,"\exmple.dll");//concentrate dll name with path
    HINSTANCE DLL = LoadLibrary(winDir);//load example dll
    if(DLL==NULL)
    {
        FreeLibrary((HMODULE)DLL);//if load fails exit
        return 0;
    }
    mainDLLFunc=(Function)GetProcAddress((HMODULE)DLL, "main");
    //defined variable is used to assign a function from dll
    //GetProcAddress is used to locate function with pre defined extern name "DLL"
    //and matcing function name
    if(mainDLLFunc==NULL)
    {
        FreeLibrary((HMODULE)DLL);//if it fails exit
        return 0;
    }
    mainDLLFunc();//run exported function 
    FreeLibrary((HMODULE)DLL);
}

回答by Yogeesh H T

extern "C"is a linkage specification which is used to call C functionsin the Cpp source files. We can call C functions, write Variables, & include headers. Function is declared in extern entity & it is defined outside. Syntax is

extern "C"是一个链接规范,用于调用Cpp 源文件中的C 函数。我们可以调用 C 函数,编写变量,并包含头文件。函数在外部实体中声明并在外部定义。语法是

Type 1:

类型 1:

extern "language" function-prototype

Type 2:

类型 2:

extern "language"
{
     function-prototype
};

eg:

例如:

#include<iostream>
using namespace std;

extern "C"
{
     #include<stdio.h>    // Include C Header
     int n;               // Declare a Variable
     void func(int,int);  // Declare a function (function prototype)
}

int main()
{
    func(int a, int b);   // Calling function . . .
    return 0;
}

// Function definition . . .
void func(int m, int n)
{
    //
    //
}