當前位置: 華文星空 > 知識

為什麽說c,c++不能跨平台,編譯器是在電腦作業系統上嗎,難道說編譯器不是在c,c++程式裏嗎?

2020-04-11知識

@pansz 的說法裏面有幾個小問題

一個是java並不是內建編譯器,而是jdk是一個比較完備的工具集合,全稱是java development kit,所以理論上,你並不需要其他工具,有jdk,其實就什麽都夠用了,但真正下發生產的時候,我們並不會把javac之類的都一並行出去,一般就是 class檔,或者jar檔,或者做了aot之後的native image,一些二進制的啟動檔,但本質上不會把編譯器一起下發,所以內建編譯器這個說法有點問題,java的編譯器就是編譯器,跟其他語言的編譯器沒有什麽不一樣,jdk你也要去下載,如果作業系統不帶c編譯器,也沒帶java編譯器

第二個是自舉,openjdk現在主流的開發語言的確是c++,hotspot是c++在編寫,但是隨著graal聖杯專案的出現,java已經實作了自舉,graal是符合jdk標準的編譯器,跟openjdk一樣,而且理論上並不依賴c去實作編譯器,理論上你可以用任何一個圖靈完備的語言,實作java的編譯器,這裏面說的依賴c去實作java的跨平台特性,那從graal誕生之後起,其實可以不這麽認為, c並非必需

然後我們正面回答問題

為什麽說c,c++不能跨平台,這裏說的不能跨平台,意思是,不能實作: 一次編譯,到處執行

java可以,當然java到處執行時候,人家讓不讓你執行那就是另外一回事了,比如app store就不讓你隨便這樣搞,要求你編譯成native,二進制機器碼

舉個例子,比如c寫了一段程式碼,我想在mac上編譯,在win上執行,可以不可以嘛?

不行吧

當然說可以用交叉編譯,那我認為交叉編譯才是跨平台,而不是你缺省的這個編譯器,這裏就引入了一個新的概念,交叉編譯

但是java我可以做到一次編譯,到處執行,而實際上我們就是這麽幹的

實作在win,mac還有linux上做好runtime,然後每次更新的時候,就不需要更新runtime,只更新 class或者jar檔,這樣就實作了一次編譯,到處執行

只要不同的平台上有對應的執行時,就可以執行我想讓它執行的程式碼,而不需要重新編譯

用這種手段,我就做到了在mac上開發,然後釋出的時候,釋出到win,mac和linux三個平台上去

c就做不到這一點,當然你可以說交叉編譯,那其實等你真的操作下去,你就會發現,不同平台上的api都他麽不一樣,格式不一樣那都是小意思,api各種不一樣,然後你就改來改去,封裝來封裝去,大量的資源和精力浪費在這種你覺得不重要的事情上,對我這種懶惰的人來說,非常不友好

java為什麽當初會流行?就是因為程式設計師們煩透了在不同作業系統上編譯來編譯去,而且c/c++編譯很慢,編譯成native沒有幾個快的,一個大專案一不小心編譯一個多小時很正常,openjdk是c++寫的,你知道編譯要多久嗎?一次2個多小時,那這種編譯的速度,每次都在這邊等等等,誰吃得消?

當然你可以說hello world編譯很快,但是問題是工作中寫的都是hello world?

相比之下,java編譯幾乎是最快的,編譯到字節碼已經很快了,而且編譯次數也不用每次都去不同平台上編譯一遍,這樣就快很多,開發起來就有效率

用流行一點的話說就是, java可以同時實作aot和jit,c只能aot,不能jit ,不考慮特殊小眾情況

這裏也沒有必要故意混淆什麽c的跨平台,我想大多數人認知的跨平台,就是java的那種跨平台,而不是各種自訂的跨平台,這裏沒有必要摳字眼

當然你說c比組譯什麽更跨平台,那是

但是我想一般人說的跨平台不是這種程度上的跨平台,畢竟現在是2021年,不是1991年

實際工作中,如果你只在源碼層面跨平台,那工作量可多了不止一倍,比如我想弄一個動態庫,要面向三個平台,那麽你要同時編譯成mac的dylib,win的dll和linux的so檔,淦,累死,java只要一個jar,搞定,而且java編譯還快,c++的編譯還慢

另外你也會擔心java的源碼可以被反編譯

我的心得,用groovy當java寫,反編譯出來的源碼內建混淆,我們實際工作中發生過的案例,有同行用kotlin寫,被人反編譯了,結果發現,淦,看不懂,遂作罷。所以如果你真的擔心被反編譯的話,除了編譯成native image也就是aot以外,你也可以混入其他jvm的語言,比如kotlin,groovy,clojure什麽都可以,反編譯出來的,一般人看不懂,尤其是groovy,你可以把groovy當java寫,而且groovy反編譯出來的源碼就跟你手寫的java源碼不一樣,破解起來難度要高很多

現在同時支持aot和jit的應該是主流了,dart,swift什麽都在朝著這個方向前進,java也不例外,c和c++其實套用面會受限,做起來太慢了,尤其是c++,現在我越來越覺得c++以後可能只是給java開發類別庫一樣的存在,專案中不會大量使用c++,你看flutter/dart,swift那邊,也都是這種情況,c++開發類別庫可以,但是一般使用者不會用c++做專案

關於java呼叫c/c++的api,類別庫這些,java有一個專案叫做panama,最近一堆人在跟他們鬧呢,因為panama又開始incubator了,然後一堆人鬧,怎麽又開始incubator了,太墨跡了,然後官方說

等panama成熟,然後graal再成熟一點,以後套用面你用c或c++主要就是寫類別庫了,常見的類別庫就是圖形相關,比如javafx,flutter,都有相當一部份的c或c++程式碼,用來封裝metal,opengl,directx之類的api

稍微前進演化一點,像2d遊戲引擎什麽,已經全部用java,kotlin [1] ,dart [2] 這種級別的語言實作了,3d還需要時間,但是我相信,遲早的事

參考

  1. ^https://github.com/AlmasB/FXGL
  2. ^https://flame-engine.org/