預處理器,編譯器,彙編器,聯結器

2021-09-26 08:14:54 字數 2383 閱讀 6489

1.2程式被其它程式翻譯成不同的格式

hello程式的生命週期是從乙個源程式(hello.c)(稱為高階c語言)開始,被其它程式轉化為一系列的低階機器語言指令,這些指令按照一種稱為可執行目標程式的格式打包好,以二進位制磁碟檔案的形式儲存。

例:unix> gcc -o hello hello.c可以實現原始檔向目標檔案的轉化,該過程由編譯程式完成。

hello.c ---->hello.i ---->hello.s ---->hello.o -->hello

(1).預處理(cpp):預處理器不止一種,而c/c++的預處理器就是其中最低端的一種——詞法預處理器,主要是進行文字替換、巨集展開、刪除注釋這類簡單工作。

gcc -e 選項可以得到預處理後的結果,擴充套件名為.i;

c/c++預處理不做任何語法檢查,不僅是因為它不具備語法檢查功能,也因為預處理命令不屬於c/c++語句(這也是定義巨集時不要加分號的原因),語法檢查是編譯器要做的事情;

預處理之後,得到的僅僅是真正的源**;

gcc確實很強大,如果是用vc這種ide,恐怕就不能看到預處理後的結果。

(2).編譯器(ccl):將文字檔案.i翻譯成文字檔案.s,得到組合語言程式(把高階語言翻譯為機器語言),該種語言程式中的每條語句都以一種標準的文字格式確切的描述了一條低階機器語言指令。

gcc -s 選項可以得到編譯後的彙編**,擴充套件名為.s;

組合語言為不同高階語言的不同編譯器提供了通用的輸出語言,比如,c編譯器和fortran編譯器產生的輸出檔案用的都是一樣的組合語言。

(3).彙編(as):將.s翻譯成機器語言指令,把這些指令打包成一種叫做可重定位目標程式的格式,並將結果儲存在目標檔案.o中(把組合語言翻譯成機器語言的過程)。

gcc -c 選項可以得到彙編後的結果,擴充套件名為.o;

.o是乙個二進位制檔案,它的位元組編碼是機器語言指令而不是字元。如果在文字編輯器中開啟.o檔案,看到的將是一堆亂碼。

把乙個源程式翻譯成目標程式的工作過程分為五個階段:詞法分析;語法分析;語義檢查和中間**生成;**優化;目標**生成。主要是進行詞法分析和語法分析,又稱為源程式分析,分析過程中發現有語法錯誤,給出提示資訊。

(4).鏈結(ld):gcc會到系統預設的搜尋路徑」/usr/lib」下進行查詢,也就是鏈結到libc.so.6庫函式中去。 函式庫一般分為靜態庫和動態庫兩種。靜態庫是指編譯鏈結時,把庫檔案的**全部加入到可執行檔案中,因此生成的檔案比較大,但在執行時也就不再需要庫檔案了。其字尾名一般為」.a」。動態庫與之相反,在編譯鏈結時並沒有把庫檔案的**加入到可執行檔案中,而是在程式執行時由執行時鏈結檔案載入庫,這樣可以節省系統的開銷。動態庫一般字尾名為」.so」,如前面所述的libc.so.6就是動態庫。gcc在編譯時預設使用動態庫。

從會敲**開始,我們就知道編譯器的重要性,沒有這東西,我們的**就是一堆字元而已。而編譯器編譯程式的步驟

主要有四個——預處理、編譯、彙編和鏈結,最後得到可執行的目標檔案。

四個步驟各自的工作會是怎麼樣的呢?不知為何,對這個東西有了點興趣。以gcc為例,主要工作是這樣的:

預處理階段會呼叫cpp,

編譯階段會呼叫cc得到匯程式設計序,

彙編階段呼叫as得到目標**,

鏈結時呼叫鏈結程式ld 得到可執行檔案。

由於四個步驟(其實本質上就是四個可執行**)早就被編譯器打包,一併替我們打理了,我們的工作是輕鬆了,

對於這幾個過程究竟是怎樣進行的,恐怕還是有個問號在腦中打轉。

後面3個階段的具體工作機制,我沒有深入了解過,但還是可以說說預處理的。

在**預處理的操作機制之前,了解預處理器是個什麼東西還是很有必要的。

預處理器不止一種,而c/c++的預處理器就是其中最低端的一種——詞法預處理器。

這種預處理器做的主要是進行文字替換、巨集展開、刪除注釋這類簡單工作。

再具體一點就是,預處理器cpp就是負責展開原始檔中的巨集,並把」#include 」的內容插入這類的工作。

空口無憑,直接上**。其實也不算空口,畢竟也谷歌、維基過了。

源**prepro.c 如下:

使用-e引數, 讓gcc在預處理之後停止編譯過程。執行:

那麼,這時預處理後的結果是怎樣的呢?貼圖如下:

有圖有真相,我們可以看到:

預處理器用stdio.h的內容替代了#include 這一行;而巨集pi也被替換為3.1415926;而且注釋也被刪除了。

總結:★ c/c++預處理器什麼都不會做,只是做巨集替換和文字替換。

★ c/c++預處理是不會做任何語法檢查的,不僅是因為它不具備語法檢查功能,也因為預處理命令

不屬於c/c++語句(這也是定義巨集時不要加分號的原因),語法檢查是編譯器要做的事情。
★ 通過預處理之後,我們得到的是也僅僅是真正的源**。

★ 還有就是,gcc這個東西確實很強大。如果是用vc這種ide,恐怕就不能看到,預處理原來是這麼個好玩的東西了。

預處理器,編譯器,彙編器,聯結器的概念和區別

好記性不如爛筆頭,所以準備詳細的記錄一下這幾個東西的功能和區別,有例子為證。參考部落格 hello程式的生命週期是從乙個源程式 hello.c 稱為高階c語言 開始,被其它程式轉化為一系列的低階機器語言指令,這些指令按照一種稱為可執行目標程式的格式打包好,以二進位制磁碟檔案的形式儲存。例 unix ...

C 編譯器與聯結器區別

編譯 編譯器對源 進行編譯,是將以文字形式存在的源 翻譯為機器語言形式的目標檔案的過程。編譯單元 對於c 來說 每乙個cpp檔案就是乙個編譯單元。各個編譯單元之間是互相不可知的。編譯器就是把我們寫的原始檔翻譯成機器 聯結器以編譯器的輸出作為輸入,生成可執行檔案。因為編譯器的編譯單元只是單獨的每個cp...

編譯器預處理實現

我們寫 一般都會寫一些注釋,為了讓人更好的理解 但是對於編譯器來說,這些注釋都需要去除,為了實現預處理,就是去除注釋 換行 回車等,我用dfa 確定有限自動機 來實現。include include using namespace std define r 10 define c 8 dfa int...