对于名称或类型具有特定语言链接意味着什么?

art*_*stv 40 c c++ standards linkage extern-c

根据(c)ANSI ISO/IEC 14882:2003,第127页:

链接规范嵌套.当链接规范嵌套时,最里面的规则确定语言.链接规范不会建立范围.链接规范只应在命名空间范围内发生(3.3).在链接规范中,指定的语言链接适用于声明引入的所有函数声明符,函数名和变量名的函数类型.

extern "C" void f1(void(*pf)(int));
// the name f1 and its function type have C language
// linkage; pf is a pointer to a C function

extern "C" typedef void FUNC();
FUNC f2;
// the name f2 has C++ language linkage and the
// function's type has C language linkage

extern "C" FUNC f3;
// the name of function f3 and the function's type
// have C language linkage

void (*pf2)(FUNC*);
// the name of the variable pf2 has C++ linkage and
// the type of pf2 is pointer to C++ function that
// takes one parameter of type pointer to C function
Run Code Online (Sandbox Code Playgroud)

这是什么意思呢?例如,f2()函数有什么链接,C或C++语言链接?

正如@Johannes Schaub所指出的那样,对于标准中的含义没有真正的解释,所以它可以在不同的编译器中进行不同的解释.

请解释目标文件中的差异:

  • 函数的名称,带有C语言链接和C++语言链接.
  • 具有C语言链接和C++语言链接的函数类型.

Vik*_*exe 16

语言链接是用于链接C++non-C++代码片段之间的术语.通常,在C++程序中,所有函数名,函数类型甚至变量名都具有默认的C++语言链接.

C++对象代码可以链接到另一个目标代码,该代码使用一些其他源语言(如C)使用预定义的链接说明符生成.

因为您必须了解name mangling编码函数名称,函数类型和变量名称的概念,以便为它们生成唯一的名称.这允许链接器区分常用名称(如在函数重载的情况下).将C模块与使用C++编译器编译的库或目标文件链接时,不希望使用名称修改.为了防止这种情况下的名称损坏,使用了链接说明符.在这种情况下,extern "C"是链接说明符.我们举一个例子(这里提到的c ++代码):

typedef int (*pfun)(int);  // line 1
extern "C" void foo(pfun); // line 2
extern "C" int g(int)      // line 3
...
foo( g ); // Error!        // line 5
Run Code Online (Sandbox Code Playgroud)

第1行声明pfun指向C++函数,因为它缺少链接说明符.

因此,第2行声明foo是一个C函数,它接受一个指向C++函数的指针.

第5行尝试使用指向g,C函数,类型不匹配的指针调用foo.

功能名称链接中的差异:

我们来看两个不同的文件:

一个有extern "c"链接(file1.cpp):

#include <iostream>
using namespace std;

extern "C"
{
void foo (int a, int b)
{
    cout << "here";
}
}

int main ()
{
    foo (10,20);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

一个没有extern "c"链接(file2.cpp):

#include <iostream>
using namespace std;

void foo (int a, int b)
{
    cout << "here";
}

int main ()
{
    foo (10,20);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在编译这两个并检查objdump.

# g++ file1.cpp -o file1
# objdump -Dx file1

# g++ file2.cpp -o file2
# objdump -Dx file2
Run Code Online (Sandbox Code Playgroud)

使用extern"C"链接,函数没有名称重整foo.所以任何正在使用它的程序(假设我们从中创建一个共享的lib)都可以直接调用foo(带有辅助函数,如dlsymdlopen),而不考虑任何名称修改效果.

0000000000400774 <foo>:
  400774:   55                      push   %rbp
  400775:   48 89 e5                mov    %rsp,%rbp
....
....
  400791:   c9                      leaveq 
  400792:   c3                      retq   

0000000000400793 <main>:
  400793:   55                      push   %rbp
  400794:   48 89 e5                mov    %rsp,%rbp
  400797:   be 14 00 00 00          mov    $0x14,%esi
  40079c:   bf 0a 00 00 00          mov    $0xa,%edi
  4007a1:   e8 ce ff ff ff          callq  400774 <foo>
  4007a6:   b8 00 00 00 00          mov    $0x0,%eax
  4007ab:   c9                      leaveq 
Run Code Online (Sandbox Code Playgroud)

另一方面,当没有extern "C"使用时,func:foo被一些预定义的规则(使用编译器/链接器已知)所破坏,因此应用程序不能直接从它指定名称来调用它foo.但是,_Z3fooii如果你愿意,你可以使用受损的名称(在这种情况下)调用它,但是没有人使用它,原因很明显.

0000000000400774 <_Z3fooii>:
  400774:   55                      push   %rbp
  400775:   48 89 e5                mov    %rsp,%rbp
 ...
...
  400791:   c9                      leaveq 
  400792:   c3                      retq   

0000000000400793 <main>:
  400793:   55                      push   %rbp
  400794:   48 89 e5                mov    %rsp,%rbp
  400797:   be 14 00 00 00          mov    $0x14,%esi
  40079c:   bf 0a 00 00 00          mov    $0xa,%edi
  4007a1:   e8 ce ff ff ff          callq  400774 <_Z3fooii>
  4007a6:   b8 00 00 00 00          mov    $0x0,%eax
  4007ab:   c9                      leaveq 
  4007ac:   c3                      retq   
Run Code Online (Sandbox Code Playgroud)

这个页面也是这个特定主题的一个很好的阅读.

关于调用约定的一篇很好且清楚解释的文章:http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx