从链接器的角度详细分析g++报错: (.text+0x24): undefined reference to `main'

发布时间 2023-10-15 08:50:23作者: Ann-

/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':

(.text+0x24): undefined reference to `main'

collect2: error: ld returned 1 exit status

 

 在使用g++编译链接两个C++源文件main.cpp以及VecAdd.cpp时出现了以上编译报错。main.cpp中引用了VecAdd.cpp中定义的函数vecAdd来实现两个向量的加法。我们先说原因,再来分析一下g++为什么会报这样的错误。出现这个error的根本原因是错误地将g++命令行指令

linux> g++ -o main main.cpp VecAdd.cpp 

写成了

linux> g++ -o main.cpp VecAdd.cpp 

这样,g++会认为我们想要对VecAdd.cpp进行编译,得到一个名为main.cpp的可执行文件。而违背了我们的本意:将main.cpp与VecAdd.cpp编译并链接,得到可执行文件main. 在实验下,以上错误的指令不仅达不成我们的目的,还会将我们的C++源文件main.cpp给吃掉,很傻:

再从链接器的角度审视一下这个错误:第一行的目录/usr/bin/ld是链接器的路径,第二行的(.text+0x24)表示目标文件出现错误的地方,也就是VecAdd.cpp对应的ELF格式的目标文件.text这一节(代码段)中地址偏移为0x24的地方。这里的undefined reference to main是什么意思? 一开始作者以为是对“main”这个符号的引用没有被定义,后来发现不是这样。做了实验后,发现真正的原因是:“在VecAdd.cpp中没有定义main函数”。我们编写了一个test.cpp.其中只有一条变量定义语句:

//test.cpp
int a = 5;

使用指令

linux> g++ -o test test.cpp

来将test.cpp编译成可执行文件,发现链接器报了同样的错误:

 于是,问题得到了解答:g++ 的 -o 选项是将源代码编译成可执行文件,而C++源程序的程序入口是main函数,在最初的例子中:

linux> g++ -o main.cpp VecAdd.cpp 

由于错误输入,这条指令这是将VecAdd.cpp编译成名为main.cpp的可执行文件,而VecAdd.cpp中实现的是向量加法函数vecAdd,该源文件并没有主函数main(),于是就出现了"undefined reference to main"的链接器报错。

可以通过使用IDE、编写shell脚本、使用cmake工具等更安全的工具,从而减少这样的失误带来的问题。