標籤:
Go 我不懂,下面以 C++ 和 C# 對比來說明為什麼 C++ 編譯慢和 C# 編譯快。
C 和 C++ 檔案的編譯經過幾個主要步驟:
- 處理續行符處理(“\”)之類的雜事
- 詞法分析,解析出 tokens 來
- 預先處理,宏展開,處理 #include ,然後對 #include 包含的檔案又重複 1~3 步驟。
- 重新詞法分析
- 文法分析產生抽象文法樹 AST
- 語義分析
- 最佳化產生代碼
C# 的步驟:
- 處理續行符處理(“\”)之類的雜事
- 詞法分析,解析出 tokens 來
- 文法分析產生抽象文法樹 AST
- 語義分析
- 最佳化產生代碼
首先,直觀的看,從編譯階段上來說 C# 就比 C++ 少,這是一個原因。
另一個原因是語言的編譯速度跟文法關係很大,進階語言編譯一般是經過詞法分析=>文法分析=>語義分析=>最佳化產生代碼幾步,如果語言的文法上沒有歧義,編譯的每個階段都是獨立的,那麼編譯速度自然就快。
如果不是這樣,文法上有歧義,比如 C++ 嵌套模板的">>"和位操作的“>>”,當編譯器遇到嵌模板">>"的時候只有先放著,然後往前多看幾步才能確定到底是模板的角括弧還是移位,自然比沒有文法歧義的語言要慢啦。
再舉個例子,C++調用模板函數執行個體化時可以省略<>讓編譯器自己去推導最合適的重載,C# 泛型方法調用也可以省略 <>。類似這樣的文法元素使得編譯器在文法分析階段就不能夠確定一個函數調用是否是函數模板執行個體化(對於 C# 來說是泛型方法調用)還是一個普通的函數調用,而要等到語義分析階段才能確定,所以在這一點上 C++ 和 C# 其實都選擇犧牲編譯速度來為人類減少擊鍵次數做貢獻並略微提高了代碼的可讀性。
還有一個方面是C和C++的編譯時間代碼產生問題產生的:標頭檔和宏定義會在編譯時間產生代碼,宏展開和引入標頭檔相當於硬插入了一大段文本,讓編譯器需要重新從詞法分析開始分析,模板什麼的雖然不是直接插入文本,但處理起來也很麻煩,消耗了不少的編譯時間。如果 C/C++ 不是用標頭檔而是某種形式的編譯模組,多個源檔案(編譯單元)引用同一個模組那麼編譯器只需分析一次該模組產生 AST 反覆使用,那編譯速度也能提升不少。
比起 C/C++ 笨笨的文本插入形式的 #include,C# 編譯器完全省去了標頭檔的編譯,你引用的 assembly 直接提供了類型和方法神馬的中繼資料,編譯器直接拿來用就好。
最後,因為 C# 沒有宏和模板之類的代碼產生手段,泛型也是運行時處理的,進一步加快了編譯速度。
----------
題外話
關於編譯器自舉跟編譯速度關係不大,目前(VS2013)的 C# 編譯器應該是 C++ 寫的,編譯速度很快,但是 Mono 的編譯器是 C# 寫的,感覺並不慢,至少沒有數量級上的差異。現在連 M$ 新的 C# 編譯器 Rosylin 也完全用 C# 寫了,還很模組化,效能也不差哦。
說了這麼多,其實我的意思是 C++ 和 C# 比 PHP 的編譯速度差遠了,PHP 是最好的語言!
為什麼 C# 比 C++ 編譯快那麼多