C语言编译流程:预处理、编译、汇编、链接
流程:
預處理:展開頭文件/宏替換/去掉注釋/條件編譯? ? ? ? ? ? ? ? ? ? ? ?(test.i main .i)
編譯:檢查語法,生成匯編? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (?test.s ?main .s)
匯編:匯編代碼轉換機器碼? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (test.o main.o)
鏈接:鏈接到一起生成可執行程序? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? a.out
?
?
1.?預處理
預編譯過程主要做4件事:
1)展開頭文件
在寫有#include <filename>或#include "filename"的文件中,將文件filename展開,通俗來說就是將fiename文件中的代碼寫入到當前文件中;
2)宏替換
3)去掉注釋
4)條件編譯
?
2.?編譯
編譯是讀取源程序(字符流),對之進行詞法、語法和語義的分析,將高級語言指令轉換為功能等效的匯編代碼。
1)詞法分析
識別單詞并分類。
詞法分析器讀入組成源程序的字符流,并將其組成有意義的詞素的序列。形如<token-name, attribute-value>這樣的詞法單元。
詞法分析的輸入是源程序,輸出是識別出的記號流.目的是識別單詞. 至少分以下幾類:關鍵字(保留字)、標識符、字面量、特殊符號
2)語法分析
組詞成句及語法錯誤檢查
語法分析器使用由詞法分析器生成的各詞法單元的第一個分量來創建樹形的中間表示。該中間表示給出了詞法分析產生的詞法單元的語法結構。常用的表示方法是語法樹,樹中每個內部節點表示一個運算,而該節點的子節點表示運算的分量。
輸入是詞法分析器返回的記號流,輸出是語法樹.目的是得到語言結構并以樹的形式表示.對于聲明性語句,進行符號表的查填,對于可執行語句,檢查結構合理的表達式運算是否有意義.
3)語義分析
分析各種語法成分的語義特征
語義分析器使用語法樹和符號表中的信息來檢查源程序是否和語言定義的語義一致?。它同時收集類型信息,并存放在語法樹或符號表中,以便在中間代碼生成過程使用。
語義分析的一個重要部分就是類型檢查。比如很多語言要求數組下標必須為整數,如果使用浮點數作為下標,編譯器就必須報錯。再比如,很多語言允許某些類型轉換,稱為自動類型轉換。
根據語義規則對語法樹中的語法單元進行靜態語義檢查,如類型檢查和轉換等,目的在于保證語法正確的結構在語義分析上也是合法的.
4)生成中間代碼(可選)
生成一種既接近目標語言,又與具體機器無關的表示,便于代碼優化與代碼生成.
5)優化中間代碼(可選)
局部優化、循環優化、全局優化等;優化實際上是一個等價變換,變換前后的指令序列完成同樣的功能,但在占用的空間上和程序執行的時間上都更省、更有效
6)生成匯編代碼
?
?
?
3.?匯編
匯編實際上指把匯編語言代碼翻譯成目標機器指令的過程,生成目標文件。
目標文件中所存放的也就是與源程序等效的目標的機器語言代碼。目標文件由段組成。通常一個目標文件中至少有兩個段:
代碼段:該段中所包含的主要是程序的指令。該段一般是可讀和可執行的,但一般卻不可寫。
數據段:主要存放程序中要用到的各種全局變量或靜態的數據。一般數據段都是可讀,可寫,可執行的。
?
?4.?鏈接
由匯編程序生成的目標文件并不能立即就被執行,其中可能還有許多沒有解決的問題。
例如,某個源文件中的函數可能引用了另一個源文件中定義的某個符號(如變量或者函數調用等);在程序中可能調用了某個庫文件中的函數,等等。所有的這些問題,都需要經鏈接程序的處理方能得以解決。
鏈接程序的主要工作就是將有關的目標文件彼此相連接,也即將在一個文件中引用的符號同該符號在另外一個文件中的定義連接起來,使得所有的這些目標文件成為一個能夠誒操作系統裝入執行的統一整體。
?
根據開發人員指定的同庫函數的鏈接方式的不同,鏈接處理可分為兩種:
(1)靜態鏈接
在這種鏈接方式下,函數的代碼將從其所在地靜態鏈接庫中被拷貝到最終的可執行程序中。這樣該程序在被執行時這些代碼將被裝入到該進程的虛擬地址空間中。靜態鏈接庫實際上是一個目標文件的集合,其中的每個文件含有庫中的一個或者一組相關函數的代碼。
(2) 動態鏈接
在此種方式下,函數的代碼被放到稱作是動態鏈接庫或共享對象的某個目標文件中。鏈接程序此時所作的只是在最終的可執行程序中記錄下共享對象的名字以及其它少量的登記信息。在此可執行文件被執行時,動態鏈接庫的全部內容將被映射到運行時相應進程的虛地址空間。動態鏈接程序將根據可執行程序中記錄的信息找到相應的函數代碼。
?
對于可執行文件中的函數調用,可分別采用動態鏈接或靜態鏈接的方法。使用動態鏈接能夠使最終的可執行文件比較短小,并且當共享對象被多個進程使用時能節約一些內存,因為在內存中只需要保存一份此共享對象的代碼。但并不是使用動態鏈接就一定比使用靜態鏈接要優越。在某些情況下動態鏈接可能帶來一些性能上損害。
?
?
?
?
?
總結
以上是生活随笔為你收集整理的C语言编译流程:预处理、编译、汇编、链接的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: webpack之polyfill踩坑之路
- 下一篇: sql中的STRFTIME
