[譯]C++, Java和C#的編譯過程解析

1.1.1 摘要

咱們知道計算機不能直接理解高級語言,它只能理解機器語言,因此咱們必需要把高級語言翻譯成機器語言,這樣計算機才能執行高級語言編寫的程序,在接下來的博文中,咱們將介紹非託管和託管語音的編譯過程。編程

1.1.2正文

非託管環境的編譯過程(C/C++)

純C/C++的程序一般運行在一個非託管環境中,類是由頭文件(.h)和實現文件(.cpp)組成,每一個類造成了一個單獨的編譯單元,當咱們編譯程序時,幾個基本組件會把咱們的源代碼翻譯成二進制代碼,接下來咱們經過如下圖片說明非託管環境的編譯過程:安全

GCC_CompilationProcess

圖1 C/C++編譯過程函數

首先是預處理器,若是在項目中有頭文件和宏表達式,那麼它將負責包含頭文件和翻譯全部的宏觀表達式。性能

接下來是編譯器,它不是直接生成二進制代碼,而是生成彙編代碼(.s),這基本上是全部現代的非結構化語言的共同基礎。優化

而後,彙編程序把彙編代碼翻譯成目標代碼(.o和.obj文件,機器指令)。.net

最後連接器,它把全部彼此相關的目標文件和生成的可執行文件或庫連接起來。翻譯

總而言之,在通常狀況下,咱們的代碼首先翻譯成彙編代碼,接着翻譯成機器指令(二進制代碼)。3d

什麼是宏?

在C/C++中,宏是預處理指令,它有多種應用技術:包括預約義、建立關鍵字和條件編譯等等。在通常狀況下,這些技術在C++中使用被認爲是很差的作法,主要緣由是有可能濫用C++提供的語法變化功能,甚至有可能在不知情狀況下建立了非標準的語言,宏不遵循通常的源代碼編譯規則,因爲它經過預處理來處理,而不是編譯器。code

託管環境的編譯過程(C#/Java)

在託管環境中,編譯的過程略有不一樣,咱們熟知的託管語言有C#和Java,接下來,咱們將以C#和Java爲例介紹在託管環境中的編譯過程。blog

當咱們在喜好的IDE中編寫代碼時,第一個檢測咱們代碼的就是IDE(詞法分析),而後,編譯成目標文件和連接到動態/靜態庫或可執行文件進行再次檢查(語法分析),最後一次檢查是運行時檢查。託管環境的共同特色是:編譯器不直接編譯成機器碼,而是中間代碼,在.NET中稱爲MSIL - Microsoft Intermediate Language,Java是字節碼(Bytecode)

在那以後,在運行時JIT(Just In Time)編譯器將MSIL翻譯成機器碼,這意味着咱們的代碼在真正使用的時候才被解析,這容許在CLR(公共語言運行時)預編譯和優化咱們的代碼,實現程序性能的提升,但增長了程序的啓動時間,咱們也可使用Ngen(Native Image Generator)預編譯咱們的程序,從而縮短程序的啓動時間,但沒有運行時優化的優勢。(JeffWong的補充Java是先經過編譯器編譯成Bytecode,而後在運行時經過解釋器將Bytecode解釋成機器碼;C#是先經過編譯器將C#代碼編譯成IL,而後經過CLR將IL編譯成機器代碼。因此嚴格來講Java是一種先編譯後解釋的語言,而C#是一門純編譯語言,且須要編譯兩次。)

 Dot_Net_Application_Compilation-707676

圖2 C#的編譯過程

.Net Framework就是在Win32 core上添加了一個抽象層,它提供的一個好處就是支持多語言、JIT優化、自動內存管理和改進安全性;另一個完整解決方案是WinRT,但這涉及到另一個主題了,這裏不做詳細介紹。

MicrosoftBoxologyDiagram

圖3 Windows API

JIT編譯的優勢和缺點

JIT編譯帶來了許多好處,最大的一個在我看來是性能的優點,它容許CLR(通用語言運行時扮演Assembler組件)只執行須要的代碼,例如:假設咱們有一個很是大的WPF應用程序,它不是當即加載整個程序,而是CLR開始執行時,咱們代碼的不一樣部分將經過一個高效的方法翻譯成本地指令,由於它可以檢查系統JIT和生成優化的代碼,而不是按照一個預約義的模式。不幸的是,有一個缺點就是啓動的過程比較慢,這意味着它不適用於加載時間長的包。

JIT的替代方案使用NGen

若是Visual Studio由JIT建立,那麼它的啓動咱們將須要等待幾分鐘,相反,若是它是使用Ngen(Native Image Generator)編譯,它將建立純二進制可執行文件,若是隻考慮速度的問題,那是絕對是正確的選擇。

1.1.3總結

在非託管環境中,咱們須要知道編譯的過程分紅編譯和鏈接兩個階段,編譯階段將源程序(*.c,*.cpp或*.h)轉換成爲目標代碼(*.o或*.obj文件),至於具體過程就是上面說的C/C++編譯過程的前三個階段;連接階段是把前面轉成成的目標代碼(obj文件)與咱們程序裏面調用的庫函數對應的代碼連接起來造成對應的可執行文件(exe文件)。

託管環境中,編譯過程能夠分爲:詞法分析、語法分析、中間代碼生成、代碼優化和目標代碼生成等等過程;不管是.NET仍是Java,它們都會生成中間代碼(MSIL或Bytecode),而後把優化後的中間代碼翻譯成目標代碼,最後在程序運行時,JIT將IL翻譯成機器碼。

不管是託管或非託管語言,它們的編譯編譯過程是把高級語言翻譯成計算機能理解的機器碼,因爲編譯過程涉及的知識面很廣(編譯的原理和硬件知識),並且本人的能力有限,也只能簡單的描述一下這些過程,若是你們但願深刻了解編譯的原理,我推薦你們看一下《編譯原理》。

參考

[1] http://www.developingthefuture.net/compilation-process-and-jit-compiler/

更新:07/31/2013

相關文章
相關標籤/搜索