1. 程式人生 > >解密C語言編譯背後的過程

解密C語言編譯背後的過程

我們大部分程式設計師可能都是從C語言學起的,寫過幾萬行、幾十萬行、甚至上百萬行的程式碼,但是大家是否都清楚C語言編譯的完整過程呢,如果不清楚的話,我今天就帶著大家一起來做個解密吧。

 

C語言相對於組合語言是一種高階語言,要想在系統上執行,需要通過編譯器把它轉換成機器能夠讀懂的可執行的程式碼。

 

以Linux系統上的gcc為例,通常我們編譯一個原始檔都是用下面的命令:

 $gcc hello.c –o hello 

 

 編譯成功後,目錄裡會生成hello這個程式,直接執行它可以看到結果。

$./hello

Hello World!

 

但hello這個程式是怎麼生成的呢,其實中間還是有好幾步的。用下面這個命令重新編譯一下,你可以看到所有的中間檔案。

$gcc -save-temps hello.c –o hello

$ls

hello hello.c hello.i hello.o hello.s

 

C編譯器的編譯過程主要分成四步:

(1) 預處理

(2) 編譯

(3) 彙編

(4) 連線

 1) 預處理 Pre-prosssing

 預處理生成了hello.i 的中間檔案,主要完成了下面幾步:

  • 去掉所有的註釋

  • 展開所有的巨集定義(也就是做字元替換)

  • 插入#include檔案的內容

  • 處理所有的條件編譯

hello.i 檔案內容如下(檔案較大,只展示了最下面的一塊):

  

可以發現原始碼中所有的註釋被刪除了,並且插入了stdio.h標頭檔案的內容。

  

2)編譯 Compiling

 編譯將 hello.i 檔案編譯生成一箇中間檔案 hello.s,開啟可以看到裡邊都是組合語言,所以編譯的作用就是把原始碼轉換成組合語言。

 

 3)彙編 Assembly

 彙編器將 hello.s 彙編成 hello.o 檔案。hello.o是二進位制檔案,裡邊都是機器可以執行的程式碼。

  

4)連線 Linking

 連線顧名思義起到了一個連線作用,雖然 hello.o 已經是二進位制檔案了,但是裡邊用到的比如 printf 函式需要呼叫別的庫。聯結器將我們的二進位制檔案和其他庫做了一個繫結。可以看到連線後生成的 hello 檔案要比 hello.o 大的多。

  

到這裡 C的完整編譯流程就結束了,本文的示例用的是Linux作業系統,編譯器用的是 gcc,但在其他作業系統,比如 Unix、Windows,或者用其他編譯器,原理都是一樣的,感興趣的同學可以去學習一下編譯原理,會對編譯有更深入的理解。