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所指出的那样,对于标准中的含义没有真正的解释,所以它可以在不同的编译器中进行不同的解释.
请解释目标文件中的差异:
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(带有辅助函数,如dlsym
和dlopen
),而不考虑任何名称修改效果.
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