C/C++之從源文件到可執行程序


搬運自我的CSDN https://blog.csdn.net/u013213111/article/details/88537509

學習了一下makefile的寫法,跟我一起寫 Makefile(一),順便看看源文件是怎么變成可執行程序的。
GCC干了些什么事情呢?在CSAPP的1.2節中講得很清楚了:


gcc有四個階段:預處理——編譯——匯編——鏈接。於是在makefile中可以明顯地看到最終的可執行目標程序依賴於一堆.o文件(可重定位目標程序),這一堆.o文件是由鏈接器ld來進行組合打包的,而.o文件又依賴於對應的.c文件(源文件)。
所以,假如有多個源文件,例如有main函數在hello.c中,在main函數中又分別調用了位於msg1.c和msg2.c中的msg1函數和msg2函數,那么gcc在編譯hello.c的過程中其實是“不涉及”msg1.c和msg2.c文件的,要用gcc hello.c msg1.c msg2.c -o hello這樣的命令分別生成三個源文件對應的.o文件,再由鏈接器把.o文件們打包組合成hello這個可執行程序。
那么就有個地方要注意了:在C語言中,函數在調用前不一定非要聲明。如果沒有聲明,那么編譯器會自動按照一種隱式聲明的規則,為調用函數的C代碼產生匯編代碼。
會產生什么樣的問題呢?參考萬惡之源:C語言中的隱式函數聲明,當隱式聲明函數名稱恰好在鏈接庫中存在,但返回非int類型時,就會導致錯誤。所以呢,強烈建議程序員重視編譯器給出的關於隱式聲明的警告,及時通過包含必要的頭文件來消除這種警告

來看看實例吧:

1 //hello.c
2 #include <stdio.h>
3 int main()
4 {
5     printf("Hello, world!\n");
6     msg1();
7     msg2();
8     return 0;
9 }
1 //msg1.c
2 #include <stdio.h>
3 void msg1(void)
4 {
5     printf("the message sent from msg1\n");
6 }
1 //msg2.c
2 #include <stdio.h>
3 void msg1(void)
4 {
5     printf("the message sent from msg2\n");
6 }

在hello.c中沒有聲明msg1和msg2這兩個函數,用gcc hello.c msg1.c msg2.c -o hello命令得到這樣的警告:

hello.c: In function ‘main’:
hello.c:5:3: warning: implicit declaration of function ‘msg1’ [-Wimplicit-function-declaration]
   msg1();
   ^
hello.c:6:3: warning: implicit declaration of function ‘msg2’ [-Wimplicit-function-declaration]
   msg2();
   ^

但是仍然生成了hello可執行文件,執行一下,輸出正常:

Hello, world!
the message sent from msg1
the message sent from msg2

那么假如在編譯的時候沒有加入msg2.c會提示什么呢?gcc hello.c msg1.c -o hello看看,除了之前的警告信息外,還有error: ld returned 1 exit status,鏈接器ld找不到要依賴的文件了。

hello.c: In function ‘main’:
hello.c:5:3: warning: implicit declaration of function ‘msg1’ [-Wimplicit-function-declaration]
   msg1();
   ^
hello.c:6:3: warning: implicit declaration of function ‘msg2’ [-Wimplicit-function-declaration]
   msg2();
   ^
/tmp/ccYSfgV0.o: In function `main':
hello.c:(.text+0x27): undefined reference to `msg2'
collect2: error: ld returned 1 exit status

上面提到的隱式函數聲明,在C++中是沒有的,對未聲明的函數進行調用會無法通過編譯,把gcc改為g++再來試試,g++ hello.c msg1.c msg2.c -o hello,果然error了:

hello.c: In function ‘int main()’:
hello.c:5:8: error: ‘msg1’ was not declared in this scope
   msg1();
        ^
hello.c:6:8: error: ‘msg2’ was not declared in this scope
   msg2();
        ^

對了,關於頭文件和源文件的關系還有一篇文章可以參考:.c和.h文件的區別


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM