1. 程式人生 > >gcc常用引數初探-來自第三章3.2的筆記-P113

gcc常用引數初探-來自第三章3.2的筆記-P113

gcc是一種C編譯器,這次我們根據書上的程式碼嘗試著使用它。

使用之前,先補充前置知識。編譯器將原始碼轉換為可執行程式碼的流程:首先,前處理器對原始碼進行處理,將#define指定的巨集進行替換,將#include包含的檔案插入,隨後,編譯器生成原始檔對應的彙編程式碼,以.s結尾。然後彙編器會將彙編程式碼轉換為機器程式碼,以.o結尾,最後,連結器將多個機器程式碼(如果有多個的話)以及程式碼中用到的庫函式(如printf)合併,產生可執行檔案。

若要比較詳細地瞭解gcc常用引數,可以參考這篇文章:

https://www.cnblogs.com/zhangsir6/articles/2956798.html

裡面講得比較詳細,當然,如果像我一樣想要以書為導向,看到不懂的再學,可以先不看那個,先繼續看下面的文章。

為了演示gcc的用法,書中演示了命令列 gcc -Og -o p p1.c p2.c的執行效果,我們需要做下實驗:

我使用的是MAC,直接開啟終端就可輸入命令列來實驗了,要注意的是p1.c和p2.c需要自己生成,且這兩個檔案必須位於當前目錄下。

首先用xcode新建個c程式,名為p1.c,裡面敲入最簡單的程式碼,如下:

 同理,再建立個p2.c,隨後將兩個檔案放到想要測試的目錄下,比如我在桌面新建了"測試gcc"資料夾:

開啟終端,使用cd指令進入到此目錄下(暫時不會linux,先用最簡單的方法,打下cd,隨後拖動對應目錄進終端,會自動把路徑匯入,如下圖)

 

 

按回車,進入此目錄:

先嚐試下

 gcc -Og -o p p1.c p2.c  這條指令,會發現居然報錯了!結果如下:

因為p1.c和p2.c都有main函式,導致報錯了,好,那現在就把p2.c的主函式註釋掉吧,如下:

重新執行指令,效果如下:

生成了名為p的可執行檔案,可以看到它沒有後綴,點開看看有什麼驚喜:

看到那個p1.clogout沒?那是p1.c的main函式中輸出的東西。

 

至此,書上的程式碼執行完畢,開始思考。

1.gcc的是區分大小寫的,這點自己試試就能發現。

2.-Og(注意,是大寫的字母O,不是數字0)代表要求gcc編譯器使用符合原始C程式碼整體結構的機器程式碼的優化等級,說白了就是編譯器在把原始碼變成機器語言時會作一定程度的優化,導致產生的機器程式碼出現了變形。同樣的,也有-O1,-O2,-O3,-O4等等優化等級,數字越大優化等級越高。-Og是在gcc 4.8版本引入的,基本相當於沒有優化。

3.編譯時可以指定檔案生成到流程的哪一步,比如-S用來指定生成彙編程式碼(以.s結尾),-c可以指定生成到機器程式碼(以.o結尾),若什麼都不輸入,則預設生成到可執行檔案,展示如下:

 

可以看到,生成的.s以及.o檔案預設都是和原始檔同名的,可執行檔案則預設命名為a.out。

3.-o是用來指定目標名稱的,可以在指定名字的時候加上對應的字尾,以生成不同型別的檔案,比如hello.exe,hello.asm等,如下圖所示:

 

這裡有個疑問,若我不生成可執行檔案,只生成.s或者.o檔案,但不想用預設的p1.s作為名字,是否能通過-o改呢?另外,改的時候如果沒有用.s作字尾名,會怎樣呢?下面是結果:

可以看到,不僅僅是可執行檔案,即使是.s檔案,也是可以用-o的方式改名的。另外,雖然這個時候名字被改變了,乃至字尾都變了,比如那個test,但其實內容和直接生成的p1.s是一樣的,可以看到它們的大小都是相同的,用文字編輯器開啟會發現內容相同。當然了,為什麼test.s和p1.s大小不同就不懂了,試著打開了test.s,結果是亂碼。。。難道是生成了機器碼嘛?

當然,以上結果對.o檔案應該也適用,簡便起見就沒做測試了。

4.我發現一個奇怪的現象,似乎gcc編譯器對語法的檢測是有限制的?

現象如下:我先把p1.c裡的main函式改個名,如mafin,此時居然能生成.s和.o檔案,直到生成可執行檔案時才報出錯來:

 

按我以前瞭解的知識,編譯器在編譯的時候不應該就直接檢測語法錯誤了嗎?為什麼生成.s時不報錯?難道以前是我記錯了,是在連結的時候檢測的?

我做了另一個實驗,把main改正常,並在main函式裡隨便打了一串字元,結果如下:

這次倒是對了,生成.s檔案的時候肯定進行了語法檢測,那隻能說明main改成mafin不算語法錯誤?不可思議,我又嘗試把main函式註釋掉,加了個函式進去,結果和第一次一樣,如下:

.s和.o能直接生成,也是到了生成可執行檔案才報錯。

好吧,我沒有耐心了,後面還有很多東西要看,姑且暫時認為main函式裡出了錯不算語法錯誤吧,可能需要學完編譯原理才能解釋這個現象。

5.還記得當時測試書上的程式碼時我們同時編譯了p1.c和p2.c嗎?如果按照那個方式寫,編譯器會分別對二者生成到.o並連結,最後生成可執行檔案,顯然,有兩個main函式會報錯的,那如果我們不生成可執行檔案,僅僅是同時生成.s和.o檔案,在存在兩個main函式的情況下,會報錯嗎?結果如下:

 

答案是:不會報錯,能同時生成。

那麼如果同時對兩個檔案生成.s,且要同時分別命名是否可以呢?結果如下:

根據提示來看,是不支援的,不管你是用gcc -S -o test1 p1.c p2.c還是妄圖施展gcc -o test1  -S p1.c -o test2 -S p2.c這樣的騷套路,統統都是行不通的。。

當然,gcc的命令引數很多很多,這兒僅僅是基於書上的內容作的一些測試和拓展,想要了解更多請看開頭的連結,讓我們愉快地結束這一節吧。

 

(有疑惑的,請看部落格的“寫在前面”一章)