编译过程中出现 'function' undefined

时间:2022-10-17 08:36:56

最近在做一个项目,包含有C++和C的代码,

在Makefile 里指定所有的cpp文件使用C++编译器(g++)编译,所有的c文件使用C编译器(gcc),

然而在编译过程中(链接阶段)出现了 xxx undefined,函数未定义的错误提示。

编译过程中出现 'function' undefined

function undefined

后来经过一番搜索,发现是linkage的问题,我也不知道这个词怎么翻译,简单的说就是要加 extern “C”

为啥要extern “C”

举个栗子好了,假如有3个文件,分别叫做
zero.h
zero.c
one.cpp

one.cpp:

#include "zero.h"
int add(int a,int b)
{
return a+b;
}
int main()
{
add(1,2);
add(3.0,4.0);
return 0;
}

 

 

zero.h:

double add(double a,double b);

 

 

zero.c:

double add(double a,double b)
{
return a+b;
}

 

 

我们先用gcc编译zero.c文件

gcc -o zero.o -c zero.c

得到zero.o文件,然后再使用g++来编译one.cpp文件

g++ -o one.o -c one.cpp

得到one.o文件,最后组装

g++ -o one zero.o one.o

发现报错了,看看

ryan@UNIX-10:~$ g++ -o one zero.o one.o
one.o: In function `main':
one.cpp:(.text+0x52): undefined reference to `add(double, double)'
collect2: error: ld returned 1 exit status

 

为啥?我们接着来看,分别看看两个.o文件的符号表

ryan@UNIX-10:~$ readelf -s one.o
Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS one.cpp
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 6
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7
7: 0000000000000000 0 SECTION LOCAL DEFAULT 5
8: 0000000000000000 20 FUNC GLOBAL DEFAULT 1 _Z3addii
9: 0000000000000014 73 FUNC GLOBAL DEFAULT 1 main
10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _Z3adddd
ryan@UNIX-10:~$ readelf -s zero.o
Symbol table '.symtab' contains 9 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS zero.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 4
8: 0000000000000000 44 FUNC GLOBAL DEFAULT 1 add

 

 

 

在one.o里面,我们看序号为10的那一条,表示

文件有对名称为_Z3adddd的项目持有引用,

但此项目并没有在此文件中(好绕口,(╯‵□′)╯︵┻━┻)

意思就是我要找_Z3adddd,但是我这个文件里没有,也许稍后我可以从其他.o文件里找。

再来看看zero.o里面,序号8,有一个名字为add的项目,但是好像真的没看到_Z3adddd。

好了,问题来了,总共就尼玛2个.o文件,无论哪里都找不到_Z3adddd的函数定义。

然后编译器就只好提示你 ‘add(double, double)’ 是个未定义的引用了。。

说好的add函数呢?

明明定义了add函数,我们在zero.h里声明,在zero.c里实现,再标准不过了,

可是为毛编译器就找不到了,还有他娘的 _Z3adddd 又是什么鬼  (生气脸

这事吧,说(lan)来(de)话(da)长(zi)。。

我们知道C编译器啊,只需要通过函数名就可以定位一个函数,

因为她不支持重载(function overloading) <–英文是不是怎么写,但愿装逼成功了。= ̄ω ̄=

然而西加加编译器啊不是,C++编译器啊,是支持函数重载的,所以她不能仅仅通过函数名来定位一个函数。

 

然而有一天,C++编译器看到这个

double add(double a,double b);
int add(int a,int b);

 

的时候,只能想想:
· 到底哪个悟空(划掉) add 函数才是真的?
· 我他妈到底要调用哪个?

· 黑人问号.jpg

所以啊,为了支持函数重载,C++还需要通过参数信息来定位一个函数,

我猜她在编译过程中,会修改函数名称来达到不可告人的(划掉)目的。 <—-这条是我瞎胡诌的,我也不知道是不是真的

这样,同样是add函数,你用C编译器编译出来的就是add,用C++编译器编译出来的就可能不是add了,而是其他的什么鬼。

道理我都懂,那怎么解决

简单说就是加extern “C” , 咱把zero.c 还有 zero.h 改改,就可以了,改成这样

zero.h:

#if __cplusplus
extern "C" {
#endif
double add(double a,double b);
#if __cplusplus
}
#endif

 

 

zero.c:

#include "zero.h"
#if __cplusplus
extern "C" {
#endif
double add(double a,double b)
{
return a+b;
}
#if __cplusplus
}
#endif

 

 

然后再编译一下one.o ,再来看看readelf返回的结果

ryan@UNIX-10:~$ g++ -o one.o -c one.cpp
ryan@UNIX-10:~$ readelf -s one.o
Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS one.cpp
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 6
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7
7: 0000000000000000 0 SECTION LOCAL DEFAULT 5
8: 0000000000000000 20 FUNC GLOBAL DEFAULT 1 _Z3addii
9: 0000000000000014 73 FUNC GLOBAL DEFAULT 1 main
10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND add

看到了么,序号为10的条目那,名字变成了add。。

 

 

就是这样,有什么说的不对的地方,你倒是来打我啊不是欢迎大家批评指正~编译过程中出现 'function' undefined