就是C++编译器编译时会改变函数的名字,要加上一些东西。比如下面的fun函数编译后用nm看成了__1cDfun6Fi_i_
之所以改函数名是因为C++允许重载,比如int fun()和int fun(int),怎么都能用fun名字呢,可以根据参数类型每个取个新名字
如果C++代码要调用C库中的函数。在C++代码申明该函数时前面要加上extern "C"
如果在C中要调用C++中的函数,那么在C++代码定义该函数时需要用extern "C"
上面两条只是一般情况,实际上这个和语言没有关系,C++加上extern "C"后也和C语言一样没有name mangle。分析时关键是分别分析定义时有没有name mangle,使用时是有没有name mangle就可以。
下面是分别用C C++编译器编译是分别不进行和进行name mangle的实例,如果申明了extern "C" C++编译器也不进行name mangle
// 1.c
int fun(int a)
{
return 0;
}
#ifdef __cplusplus
extern "C"
#endif
int externcfun()
{
return 0;
}
CC -c 1.c -o mangle.o
cc -c 1.c -o nomangle.o
$nm mangle.o
mangle.o:
[Index] Value Size Type Bind Other Shndx Name
[3] | 0| 0|SECT |LOCL |0 |5 |
[2] | 0| 0|SECT |LOCL |0 |6 |
[1] | 0| 0|FILE |LOCL |0 |ABS |1.c
[5] | 16| 36|FUNC |GLOB |0 |2 |__1cDfun6Fi_i_ // C++编译器进行了name mangle
[4] | 72| 32|FUNC |GLOB |0 |2 |externcfun // 申明了extern "C"时,即使C++编译器也不name mangle
$nm nomangle.o
nomangle.o:
[Index] Value Size Type Bind Other Shndx Name
[2] | 0| 0|SECT |LOCL |0 |10 |
[3] | 0| 0|SECT |LOCL |0 |9 |
[1] | 0| 0|FILE |LOCL |0 |ABS |1.c
[4] | 0| 0|OBJT |LOCL |0 |3 |Bbss.bss
[5] | 0| 0|OBJT |LOCL |0 |4 |Ddata.data
[6] | 0| 0|OBJT |LOCL |0 |5 |Drodata.rodata
[7] | 72| 32|FUNC |GLOB |0 |2 |externcfun
[8] | 16| 36|FUNC |GLOB |0 |2 |fun // c编译器没有name mangle
实际上这个和语言没有关系,主要看编译后的名字是什么,分析这类问题时按照编译生成的函数名。在看使用时和定义是是否一致
比如
// 1.cpp
int externcfun()
{
return 0;
}
// main.cpp
extern externcfun();
int main()
{
externcfun();
return 0;
}
CC 1.cpp main.cpp没有问题
1.cpp 改成下面的,增加了extern "C" // 也就是都是C++编译器也会变异不过,因为定义时没有name mangle,链接使用时按照有name mangle找函数名字,当然找不到
extern "C" int externcfun()
{
return 0;
}
再用上面的CC 1.cpp main.cpp编译报错
Undefined first referenced
symbol in file
int externcfun() main.o
ld: fatal: Symbol referencing errors. No output written to a.out
解决上面错误的方法是在main.cpp中申明externcfun时加上extern "C"
// main.cpp
extern "C" externcfun();
int main()
{
externcfun();
return 0;
}
阅读(1047) | 评论(0) | 转发(0) |