從連結器的角度詳細分析g++報錯: (.text+0x24): undefined reference to `main'

發表於2023-10-15

/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工具等更安全的工具,從而減少這樣的失誤帶來的問題。

相關文章