根据(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这一切意味着什么?例如,f2()函数有哪些链接,C或C++语言链接?
正如@Johannes Schaub所指出的,对标准中的含义没有真正的解释,因此在不同的编译器中可以对其进行不同的解释。
请解释对象文件中的不同之处:
发布于 2011-05-19 14:56:28
语言链接是指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第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;
}一个没有extern "c"链接(file2.cpp):
#include <iostream>
using namespace std;
void foo (int a, int b)
{
cout << "here";
}
int main ()
{
foo (10,20);
return 0;
}现在编译这两个并检查objdump。
# g++ file1.cpp -o file1
# objdump -Dx file1
# g++ file2.cpp -o file2
# objdump -Dx file2使用extern "C“链接,函数foo没有名称损坏。因此,任何正在使用它的程序(假设我们利用它创建一个共享库)都可以直接调用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 另一方面,当不使用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 对于这个特定的主题,此页也是很好的读物。
一篇很好而且解释清楚的关于调用约定的文章:demystified.aspx
发布于 2011-05-18 08:22:41
“名称f2有C++语言链接”在C++语言链接中不仅定义了函数的名称,而且定义了it参数的类型和返回值。在本例中,您有: void f2( void );但是您可以用它定义:void f2(int a);没有冲突,因为链接会将它们看作不同的类型,这在C语言中是无法做到的。
“函数的类型有C语言链接”,我不知道细节,但我知道它的高层次。基本上,它使C++编译的函数可以从C链接到C,如果我正确地记得C和C++中参数传递给函数的方式是不同的。在这种情况下,函数f2将像C编译器那样传递参数。这样,函数就可以从C和C++连接起来。
发布于 2011-05-19 15:21:40
extern "C" typedef void FUNC();
FUNC f2;
// the name f2 has C++ language linkage and the
// function's type has C language linkage名称FUNC是用"C“链接声明的,因为它在第一行上写的是extern "C"。
名称f2有C++链接,因为这是默认的,第2行没有给出其他链接。
名称f2用于引用具有C链接的函数这一事实并不改变名称的链接。
https://stackoverflow.com/questions/5763919
复制相似问题