Name mangling is the encoding of function and variable names into unique names so that linkers can separate common names in the language.
Name mangling实际上是对函数(或者变量)名称的一种编码,c++支持函数重载,而c不支持。所以c++的函数签名的编码方式肯定是和c不一样的,举个例子:
int foo(int a); // foo
int foo(int a); // foo(int)
int foo(float a); // foo(float)
也可以理解为,函数原型经过编码之后得到的唯一id,暴露给linker用的。linker根据这个名字去查找、链接相应的函数地址。
同样一段c代码,用c compiler和c++ compiler编出来的函数&变量名称是不一样的。c++的通常会复杂一些,包含namespace,class,形参类型列表等。当使用c++ compiler且不想要上述mangling的时候,可以使用:
extern "C" {
int foo(int a);
void bar(int b);
}
来告诉编译器这些名字不要进行name mangle. 这在c调用c++方法时尤其有用。
场景一:C调用C++
C++头文件中提供函数声明,C的源文件中需要包含这个头文件,并使用这个函数。
// file: cpp.h
#ifdef __cplusplus
extern "C" {
#endif
int foo(float);
#ifdef __cplusplus
}
#endif
// file: c.c
#include "cpp.h"
int main()
{
int a = foo(3.14f);
return 0;
}
使用gcc编译c.c,头文件中的__cplusplus
宏处于未定义状态,int foo(float)
,foo的函数原型不会进行name mangling,直接就是foo
. 因此cpp.h可以用于C项目中。
使用g++编译其他cpp文件,包含cpp.h,此时__cplusplus
宏处于定义状态,extern C的效果产生,即告诉g++不要给int foo(float)
进行name mangling,此时编译出的符号,也可以直接用于C++项目,也可以编出lib给C项目使用。
场景二:C++调C
C中实现了某些函数,在某个头文件中声明了这些函数。例如
// file: c.h
#ifdef __cplusplus
extern "C" {
#endif
int foo();
char bar(char);
#ifdef __cplusplus
}
#endif
这里的__cplusplus
宏,在原生C项目中(gcc编译)处于未定义状态,压根不起作用。但在C++项目(g++编译)中,如果包含了这个头文件,读到了__cplusplus
宏,就不会对foo和bar进行name mangling,因此,C++链接器在寻找这个符号时,能够正确找到此前用gcc生成的未进行name mangling的符号。
c.h中的函数实现,必然在某个C源文件中。因此一般使用gcc编译产生lib. C++要用这个lib,要能找到这个符号,就必须按之前C语言的符号生成规则(不进行name mangling)来寻找(链接)。
You will need extern "C"
both when calling:
- C from C++: tell
g++
to expect unmangled symbols produced bygcc
, - C++ from C: tell
g++
to generate unmangled symbols forgcc
to use.
See also 链接