為什么 C 語(yǔ)言仍然占據統治地位? 為什么 C 語(yǔ)言仍然占據統治地位? C語(yǔ)言五十年來(lái)一直是軟件開(kāi)發(fā)的一種主力語(yǔ)言。以下是它在如今的2019年與C ++,Java,C#,Go,Rust和Python抗衡的方式。 file:///C:\Users\Administrator.WIN-STED6B9V5UI\AppData\Local\Temp\ksohtml6596\wps6.png 翻譯:CSDN 沒(méi)有什么技術(shù)可以應用長(cháng)達50年之久,除非它真的比大多數其他東西都要好用——對于一種計算機行業(yè)的技術(shù)來(lái)說(shuō)尤其如此。自1972年誕生以來(lái),C語(yǔ)言一直保持生龍活虎的狀態(tài),時(shí)至今日它仍然是我們用來(lái)搭建軟件世界的基礎建筑材料之一。 但有時(shí)一種技術(shù)能夠長(cháng)期存在,只是因為人們還沒(méi)有來(lái)得及發(fā)明新的東西來(lái)取代它而已。在過(guò)去的幾十年里,出現了許多其他語(yǔ)言——其中一些明確地被設計用于挑戰C的主導地位,有些語(yǔ)言試圖憑借自己的人氣慢慢瓦解C語(yǔ)言的統治地位。 為C需要被替換掉的觀(guān)點(diǎn)爭辯是簡(jiǎn)單的。編程語(yǔ)言研究和軟件開(kāi)發(fā)實(shí)踐都暗示了如何比C更好地去做事。但歷經(jīng)數十年的研究和開(kāi)發(fā),C語(yǔ)言的地位卻依舊穩固。很少有其他語(yǔ)言能夠在性能、裸機兼容性或通用性等方面擊敗它。不過(guò),2018年C是如何與那些明星編程語(yǔ)言競爭的呢,其中細節仍值得一看。 01 C vs. C ++ 當然了,C最常被拿來(lái)與C ++進(jìn)行比較,正如其名稱(chēng)本身所暗示的那樣,C++作為對C語(yǔ)言的擴展而被創(chuàng )建出來(lái)。C ++和C之間的差異可以概括為C++更加廣泛(褒)或更加寬泛(貶),具體取決于這個(gè)問(wèn)題你是問(wèn)的C還是C++程序員。(笑) 雖然C ++的語(yǔ)法等方面仍然是類(lèi)C的,但它提供了許多在原生的C中本不可用的非常實(shí)用的功能:命名空間(namespace),模板(template),異常(exception),自動(dòng)內存管理(automatic memory management)等等。需要頂級性能的項目,例如涉及數據庫,機器學(xué)習系統的項目通常是用C ++編寫(xiě)的,以便項目能盡可能地榨取以及利用到每一點(diǎn)性能。 此外,與C相比,C ++在持續地更加積極地擴展。即將推出的C ++ 20會(huì )帶來(lái)更多功能供開(kāi)發(fā)者享用,包括模塊,協(xié)同程序,同步庫,以及概念,這些使模板更易于使用。C standard的最新版本只進(jìn)行了少量更新,并側重于保持向后兼容性。 事實(shí)上,C ++ 中的所有附加功能同樣也可能成為累贅。而且是很大的累贅。您使用的C ++專(zhuān)屬功能越多,引入的復雜度就越高,對結果的修正就越困難。將自己局限于僅一個(gè)C ++子集的開(kāi)發(fā)人員可以避免許多開(kāi)發(fā)中嚴重的坑和額外負擔。但是有些團隊想要從根兒上防范C ++的過(guò)度復雜性。堅持使用C能迫使開(kāi)發(fā)人員將自己局限于一個(gè)子集。例如,Linux內核開(kāi)發(fā)團隊就直接避開(kāi)了C ++。 選C而不選C++對您——以及任何將會(huì )維護你代碼的開(kāi)發(fā)人員——來(lái)說(shuō)都是可行的,通過(guò)采用強制簡(jiǎn)約主義來(lái)避免與C ++的復雜性糾纏。當然,C ++擁有豐富的高級功能,這是有它自己的道理的。但如果極簡(jiǎn)主義更適合當前和未來(lái)的項目——以及負責項目的團隊——那么還是選C更明智一些。 02 C vs. Java 幾十年了,Java仍然是企業(yè)軟件開(kāi)發(fā)的主力軍之一——并且也是寬泛而言的開(kāi)發(fā)的主力軍之一。許多最重要的企業(yè)軟件項目都是用Java編寫(xiě)的——包括絕大多數Apache Software Foundation項目——而Java仍然是開(kāi)發(fā)企業(yè)級需求項目的可行語(yǔ)言。 Java的語(yǔ)法從C和C ++中借鑒了很多東西。但是,與C不同的是,Java默認情況下不會(huì )編譯為本機代碼。相反,Java運行時(shí)環(huán)境,JVM,JIT(實(shí)時(shí))編譯Java代碼以在目標環(huán)境中運行。在適當的情況下,JIT編譯后的Java代碼可以接近甚至超過(guò)C的性能。 Java背后的“一次編寫(xiě),隨處運行”的理念也允許Java程序在目標架構上進(jìn)行相對較少的調整即可運行。相比之下,雖然C已被移植到許多架構中,但任何給定的C程序仍可能需要重新量身定做才能在,打個(gè)比方,Windows與Linux,兩種不同的os之間正常運行。 這種可移植性和強大性能的結合,以及龐大的軟件庫和框架組成的生態(tài),使Java成為構建企業(yè)應用程序的首選語(yǔ)言。 Java輸給C的地方是一個(gè)Java從未打算競爭的領(lǐng)域:靠近底層結構運行,或直接與硬件打交道。C代碼被編譯成機器代碼,由進(jìn)程直接執行。Java被編譯成字節碼,這是一種隨后會(huì )被JVM解釋器轉換為機器代碼的中間代碼。此外,盡管Java的自動(dòng)內存管理在大多數情況下都是個(gè)優(yōu)點(diǎn),但C更適合于必須充分利用有限內存資源的情況。 也就是說(shuō),在某些方面,Java在速度方面可以接近于C。JVM的JIT引擎在運行時(shí)根據程序行為優(yōu)化例程,允許進(jìn)行許多類(lèi)型的優(yōu)化,而這些優(yōu)化是在未提前編譯的C中無(wú)法實(shí)現的。雖然Java運行時(shí)自動(dòng)執行內存管理,但一些較新的應用程序可以解決這個(gè)問(wèn)題。例如,Apache Spark部分地通過(guò)使用繞過(guò)JVM的自定義內存管理代碼來(lái)優(yōu)化內存中處理。 03 C vs. C#和.Net 在推出近二十年后,C#和.Net 框架仍然是企業(yè)軟件世界的主要組成部分。有人說(shuō)C#和.Net是微軟對Java的回應——一個(gè)托管代碼編譯器系統和通用運行庫——C和Java之間的許多種對比也適用于C和C;.Net之間。 與Java(以及某種程度上來(lái)說(shuō)Python也是如此)一樣,.Net提供跨各種平臺的可移植性和龐大的集成軟件生態(tài)系統?紤]到.Net世界中有多少面向企業(yè)的開(kāi)發(fā),這些都是不小的優(yōu)勢。當您使用C;蛉魏纹渌.Net語(yǔ)言開(kāi)發(fā)程序時(shí),您可以使用為.Net運行時(shí)編寫(xiě)的大量工具和庫。 .NET另一個(gè)類(lèi)似Java的優(yōu)勢是JIT優(yōu)化。C#和.Net程序可以按照C語(yǔ)言提前編譯,但它們主要由.Net運行時(shí)進(jìn)行即時(shí)編譯,并使用運行時(shí)信息進(jìn)行優(yōu)化。JIT編譯允許對無(wú)法在C中執行的運行著(zhù)的.Net程序進(jìn)行各種就地優(yōu)化。 與C一樣,C#和.Net提供各種直接訪(fǎng)問(wèn)內存的機制。堆,棧和非托管系統內存都可以通過(guò).Net API和對象訪(fǎng)問(wèn)。開(kāi)發(fā)人員可以使用.Net中的unsafe模式來(lái)實(shí)現更高的性能。 但這些都不是沒(méi)有代價(jià)的。托管對象和unsafe對象不能被任意交換,并且它們之間的編組會(huì )降低性能。因此,要最大化.Net應用程序的性能需要將托管和非托管對象之間的變動(dòng)保持在最低限度。 如果您無(wú)法承擔托管與非托管內存之間變動(dòng)造成的性能損失,或者.Net運行時(shí)對于目標環(huán)境(例如,內核空間)來(lái)說(shuō)是一個(gè)糟糕的選擇,或者可能根本不可用,那么C就是你所需要的。與C#和.Net不同,C被默認可以解鎖對內存的訪(fǎng)問(wèn)權。 04 C vs. Go Go的語(yǔ)法很大程度上借鑒了C——花括號作為定界符,語(yǔ)句以分號結束,等等。精通C的開(kāi)發(fā)人員通?梢院敛毁M力地直接使用Go,甚至算上Go的獨有功能,如命名空間和包管理,對開(kāi)發(fā)人員來(lái)說(shuō)也并不困難。 代碼可讀性是Go的指導設計目標之一:讓開(kāi)發(fā)人員可以輕松掌握任何Go項目,并在短時(shí)間內熟練掌握代碼庫。C代碼庫可能很難理解,因為它們很容易聚集大量專(zhuān)屬于某個(gè)項目或某個(gè)團隊的宏和和#ifdef。Go的語(yǔ)法及其內置的代碼格式以及項目管理工具旨在避免這種結構性問(wèn)題。 Go還提供了諸如goroutine和channel之類(lèi)的附加功能,用于處理并發(fā)性和組件之間的消息傳遞的語(yǔ)言級別的工具。C需要開(kāi)發(fā)者手動(dòng)完成或由外部庫提供,但Go提供了開(kāi)箱即用的這些功能,使得構建需要這些功能的軟件變得更加容易。 Go與C最深層次的不同之處在于內存管理方面。默認情況下,Go的對象會(huì )被自動(dòng)管理并自動(dòng)進(jìn)行回收。對于大多數編程工作來(lái)說(shuō),這非常方便。但這也意味著(zhù)任何需要確定性處理內存的程序都會(huì )更難編寫(xiě)。 Go確實(shí)包含了用于繞過(guò)Go的某些類(lèi)型處理安全性的unsafe包,例如使用Pointer類(lèi)型讀取和寫(xiě)入任意內存。但unsafe會(huì )附帶一個(gè)warning說(shuō)用它編寫(xiě)的程序“可能是不可移植的,并且不受Go 1兼容性指南的保護。 ” Go非常適合構建命令行實(shí)用程序和網(wǎng)絡(luò )服務(wù)等,因為這些很少用到太過(guò)細致的操作。但是,如果是低級設備驅動(dòng)程序,內核空間操作系統組件以及其他需要嚴格控制內存布局和管理的任務(wù),那么就最好用C來(lái)創(chuàng )建。 05 C vs. Rust 在某些方面,Rust是對C和C ++創(chuàng )建的內存管理難題的回應,也是對這兩種語(yǔ)言的許多其他缺點(diǎn)的回應。Rust編譯為本機機器代碼,因此就性能而言,它被認為與C相當。但默認情況下,內存安全才是Rust的主要賣(mài)點(diǎn)。 Rust的語(yǔ)法和編譯規則可幫助開(kāi)發(fā)人員避免常見(jiàn)的內存管理錯誤。如果程序有一個(gè)不符合Rust語(yǔ)法的內存管理問(wèn)題,它就不會(huì )被編譯。剛接觸這種語(yǔ)言的新手,特別是以前用C語(yǔ)言的開(kāi)發(fā)者,由于C語(yǔ)言為這類(lèi)bug提供了充足的容錯空間,所以他們接觸Rust的第一步是學(xué)習如何安撫編譯器。但Rust的支持者認為,這種短期的痛苦有一個(gè)長(cháng)期的回報:更安全的,不會(huì )減緩速度的代碼。 Rust還通過(guò)其工具改進(jìn)了C語(yǔ)言。默認情況下,項目和組件管理是Rust提供的工具鏈的一部分,與Go相同。有一種默認的,推薦的方法來(lái)管理包,組織項目文件夾,以及處理C需要單獨處理的其他許多事情,每個(gè)項目和團隊以不同的方式處理它們。 然而,在Rust中被吹捧為優(yōu)勢的東西對于C開(kāi)發(fā)者來(lái)說(shuō)可能并沒(méi)有太大吸引力。Rust的編譯時(shí)安全功能無(wú)法禁用,因此即使是最小的Rust程序也必須符合Rust的內存安全限制。默認情況下,C可能不太安全,但在必要時(shí)它更靈活,更寬容。 另一個(gè)可能的缺點(diǎn)是Rust語(yǔ)言的大小。即使考慮到標準庫,C的功能也相對較少。Rust功能集非常龐大并且還在不斷增長(cháng)。與C ++一樣,較大的Rust功能集意味著(zhù)更強大的功能,但也意味著(zhù)更高的復雜度。C是一種較小的語(yǔ)言,但更容易在頭腦中進(jìn)行建模,因此可能更適合那些對Rust來(lái)說(shuō)太小,不值得大動(dòng)干戈的項目。 06 C vs. Python 當今,每當談?wù)撥浖_(kāi)發(fā)時(shí),Python似乎總是能出現在對話(huà)中。畢竟,Python是“對所有項目的第二佳語(yǔ)言”,毫無(wú)疑問(wèn)是最通用的語(yǔ)言之一,擁有數千個(gè)第三方庫。 Python強調的,以及它與C最不同的地方,是有利于開(kāi)發(fā)速度而不是執行速度。一個(gè)可能需要一個(gè)小時(shí)才能用另一種語(yǔ)言寫(xiě)出來(lái)的程序——比如C——可能用Python幾分鐘內就能寫(xiě)好。另一方面,該程序在C中執行可能需要幾秒鐘,但需要一分鐘才能在Python中運行完。(一個(gè)很好的經(jīng)驗法則:Python程序通常比它們對應的C語(yǔ)言程序運行速度慢一個(gè)數量級。)但是對于現代硬件上的許多工作,Python已經(jīng)足夠快了,這是它如今廣泛應用的一個(gè)重要原因。 另一個(gè)主要區別是內存管理。Python程序完全由Python運行時(shí)進(jìn)行內存管理,因此開(kāi)發(fā)人員不必擔心分配和釋放內存的細節。但同樣,開(kāi)發(fā)人員的輕松也是以運行時(shí)性能為代價(jià)的。編寫(xiě)C程序需要嚴格關(guān)注內存管理,但生成的程序通常是純機器速度的黃金標準。 但是,在二者的血脈中,Python和C共享一個(gè)深層的關(guān)系:Python運行時(shí)參考是用C語(yǔ)言編寫(xiě)的。這允許Python程序包裝用C和C ++編寫(xiě)的庫。第三方庫的Python生態(tài)系統的很多重要模塊,例如機器學(xué)習方面的庫,其核心是C代碼。 如果開(kāi)發(fā)速度比執行速度更重要,并且如果程序的大多數高性能部分可以被隔離到獨立組件中(而不是遍布整個(gè)代碼),那么純Python或Python和C庫的混合使得會(huì )是比單獨使用C更好的選擇。否則的話(huà),C仍然是老大。
|