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 是最好的語言!