简体   繁体   English

外部“C”声明如何工作?

[英]How does an extern “C” declaration work?

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++"? 除了“它接口C和C ++”之外,这个声明如何在更深层次上工作? How does this affect the bindings that take place in the program as well? 这又如何影响程序中发生的绑定?

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 00000010 T _Z3barv

00000000 T foo 00000000 T foo

foo() keeps its name. foo()保留其名称。

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. 现在在C中,该函数在内部称为“_Add”。 Whereas the C++ function is called something completely different internally using a system called name-mangling. 而使用名为name-mangling的系统在内部完全不同地调用C ++函数。 Its basically a way to name a function so that the same function with different parameters has a different internal name. 它基本上是一种命名函数的方法,以便具有不同参数的相同函数具有不同的内部名称。

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. 因此,如果在add.c中定义了Add(),并且你在add.h中有原型,那么如果你试图在一个C ++文件中包含add.h,你就会遇到问题。 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. 因为C ++代码正在寻找名称与add.c中的名称不同的函数,所以会出现链接器错误。 To get around that problem you must include add.c by this method: 要解决该问题,您必须通过此方法包含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”{...}声明来包装它。

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 ++样式名称修改(支持运算符重载更复杂)。

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. 在C ++中,函数的名称/符号实际上被重命名为其他类,以便不同的类/命名空间可以具有相同签名的函数。 In C, the functions are all globally defined and no such customized renaming process is needed. 在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约定。

It should be noted that extern "C" also modifies the types of functions. 应该注意, extern "C"也修改了函数的类型。 It does not only modify things on lower levels: 它不仅修改较低级别的内容:

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

void foo();

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

The type of &foo does not equal the type that the typedef designates (although the code is accepted by some, but not all compilers). &foo的类型不等于typedef指定的类型(虽然代码被某些编译器接受,但并非所有编译器都接受)。

extern C affects name mangling by the C++ compiler. extern C通过C ++编译器影响名称修改。 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. 它是一种让C ++编译器不会破坏名称的方法,或者更确切地说是以与C编译器相同的方式来破坏它们。 This is the way it interfaces C and 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. 当试图让C模块调用C ++模块中定义的C ++函数(显然C不能使用C ++类)时,就会遇到麻烦。 The C compiler doesn't like extern "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 ++代码调用。

extern "C" denotes that the enclosed code uses C-style linking and name mangling. extern“C”表示附带的代码使用C风格的链接和名称修改。 C++ uses a more complex name mangling format. C ++使用更复杂的名称修改格式。 Here's an example: 这是一个例子:

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在评论中指出的那样,名称修改的模式依赖于编译器。

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'的类型信息

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM