C 語言高效得簡直不合理

類別: IT

【譯者序:我翻譯此文並非推崇C而貶低其他語言。我翻譯此文,只是因為作者的多處精到的見解讓人深思。作者的出發點,很明顯,是純技術的;各位讀者且謹記這一點。】

多年來,我一直試圖擺脫C語言。太簡單,太多細節需要處理,太古老,太低階。我一直鍾愛Java,C++,Erlang。我用它們建立了很多專案,並且自己為這些專案感到驕傲;然而,這些語言,最終,都傷了我的心。他們做出承諾,卻無法兌現;他們專注於錯誤的東西,並且所做的“折衷”最終讓你倍感煎熬。於是,我不得不求助於C。

C就是一個萬能揹包。它高效且高產,有強大的工具和廣泛的社群支援,並且它對它所做的“折衷”非常誠實。

對於其他語言,他們能讓你更快的工作,但從長遠來看,當效能和可靠性變得重要時,C將會為你省去不少麻煩事兒。我個人再次非常痛苦的學到了這一刻。


簡單直觀

C語言是非常棒的高階語言。我重複一遍,C語言是非常棒的高階語言。當然,它沒有Java、C#等高階,自然也沒有Erlang、Python或者Javascript高階。但是,他和C++在語言的高階程度上,是一樣的;而然它比C++更加簡單。當然C++提供了更多的抽象,然而它並沒有給出比C更高階的抽象。在使用C++時,你考慮的細節並不比你使用C時的少,除此之外,你還要考慮一堆可笑的無意義東西。

"When someone says: 'I want a programming language in which I need only say what I wish done', give him a lollipop." - Alan J. Perlis
當有人說:“我想要一種程式語言,我僅需要對它說我想幹啥就行了。”那麼給那個小屁孩兒一個棒棒糖吧。 Alan J. Perlis

我們想要找一種低階語言來代替C,然而找不到;這並非是因為C語言是低階語言,相反,恰恰是因為C語言作為底層機器上的高層抽象太成功了。它如此成功,以至於讓大多數的低階語言顯得毫無意義。C就是這麼擅長它所做的。

C語言的語法和語義強大而直觀。它可以用以編寫高階演算法,同時也可以用以處理底層硬體邏輯。正因為其強大、簡單和直觀的語法和語義,C語言並不會給我們一些額外的認知上的負擔,從而讓程式設計者專注於真正重要的事情。

C顛覆了我們對低階語言的認識。這真了不起。

簡單的程式碼,精緻的型別

c語言是一種弱型別語言,其型別系統非常簡單。和C++還有java明顯的一個區別是,c裡面你不能定義“類”(class),你不可以把所有的執行時需要的東西都放到“類”裡面。你的所有工作都嚴格基於結構(struct)和聯合(union)。所有的函式呼叫者必須明確被呼叫函式的引數型別和返回值型別。所以呼叫者的自由相對有限。

你只是想要個香蕉,結果來了只自稱森林之王的大猩猩——Joe Armstrong

你剛剛聽起來像是c語言缺點的東西某種程度上確實一種優點:c語言的API面對使用者都力圖精簡。這避免了龐雜的框架,而力圖在簡單的型別基礎上創造一個小巧的函式庫。

而物件導向的語言往往在複雜的型別基礎上又構造了龐雜的基礎類庫,這些庫提供了大量的相互依賴的介面,他們的引數和返回值的“類”型也因此更加複雜。每一種“類”又定義了大量的複雜的方法和屬性……好吧,更加複雜了。

這並不是說吐物件導向就希望變複雜,但是他們貌似鼓勵你把事情變複雜。他們的複雜性使你很容易犯錯誤。相對來說,c就很少導致錯誤。c語言盡力構建一個簡潔、通俗的型別系統,使用它你會發現你不需要顧及那麼多的依賴關係。這使你的開發變得更加簡單。

速度之王

c語言不論在處理器中還是在記憶體堆疊裡,都是速度最快的。而且其高效不僅僅體現在速度上,即使是記憶體的管理以及啟動時間上,也無人望其項背。當你需要平衡空間和時間的消費時,c語言從來不會對你隱藏任何細節,原因如下:

-強大的編譯器
-k&p風格
每次那些更高層次的程式語言(比如java或者haskell),聲稱自己能產生接近c語言的表現從程式的時候,這在我聽來簡直就是笑話。通常,他們為了實現這一點,不得不在語法上做出一些稀奇古怪的事情,比如專門搞一些“聰明的”編譯器或者虛擬機器……這種古怪的優化行為使語言失去了原本簡單的性質,更何況這種優化往往只是針對處理器

當你想要用c語言寫一些對執行速度要求嚴格的東西時,你可以很清楚的知道為什麼他很快,這一點不因為你使用的編譯器或者虛擬機器不同而改變。應用程式中,GC(垃圾回收)的設定將會影響執行。而人機互動將會影響垃圾回收對於資料的處理。

c語言的程式碼優化直接而有效。即使你不這樣認為,在實際工作中也有大量的工具幫助你瞭解其中的緣故。相對來說,你根本沒有必要為此壯起膽子去嘗試學習什麼虛擬機器,什麼“智慧優化編譯器”。當你在使用cpu,記憶體和IO分析器的時候,c語言絕對不會讓你對底層到底發生了什麼感到困惑。以上所言,不論是從處理器的角度還是從記憶體堆疊角度,都證明了c語言是速度之王。

更快的“編寫-執行-除錯”週期

“編寫-執行-除錯”這個開發週期對於程式員是十分重要的。如果這個週期足夠快,開發中的人機互動足夠多,那麼你的任務就進行的足夠迅速。c具有主流靜態型別語言中最快速的人機互動效能。

樂觀是程式員的職業病,返工是他們的唯一藥方 -Kent Beck
因為“編寫-執行-除錯”週期更多的是一種開發工具的使用原則而並不是一個語言的核心,所以他經常被忽略。雖然如此,怎麼宣揚這個迴圈對於開發速度的攻擊都不為過。悲催的是,這一迴圈已經被很多變成語言遺忘了,他們反而去追求使用中的程式碼的可讀性。所以,事實是,c仍然是最快的語言。

除錯以及核心轉儲

對於任何你想將你的程式碼移植過去的系統,你幾乎都可以發現一些c語言除錯工具和核心轉儲工具。他們對於你能夠快速找到原始碼中的問題所在是非常重要的。當然,他們也可能出現問題。

Error, no keyboard -- press F1 to continue.
對於其他的程式語言來說,就沒有這麼多的工具了。不論如何你都得承認,這些工具對於你c語言的變成起了十分重要的作用。假如要你寫一個c語言與其他語言的介面,或許你費了九牛二虎之力,卻做出了一個結構十分複雜,執行十分脆弱,使用根本白瞎的廢物。

如果是純粹用c寫的程式,你可以察看呼叫堆疊,變數,引數,當前執行緒……一切的記憶體當中最基礎的東西都毫髮畢見。這真的很有效,尤其是當你面對一個已經宕機幾天的伺服器程式而無計可施。而當你面對一個用其他高階語言寫就的程式是……準備受死吧……

從任何地方呼叫

C有一個標準化的應用程式二進位制介面(ABI)支援每個作業系統,語言和平臺的存在。它不需要執行或其他固有的開銷。這意味著你編寫的程式碼在C不僅是有價值的,從C程式碼的呼叫方,但對於每一個可以想象的包,在語言和環境中還是存在。

"Portability is a result of few concepts and complete definition"

- J. Palme

您可以使用獨立的可執行檔案,指令碼語言,核心程式碼中,嵌入程式碼的C程式碼,作為一個DLL,甚至從SQL呼叫。這是用得上系統程式設計和可插拔庫。如果你想要寫的東西一旦有可用的最可能的環境和使用情況,C是唯一明智的選擇。

是的!它有瑕疵

在C語言中有許多”瑕疵“ 。它沒有邊界檢查,很容易發生記憶體衝突,有懸空指標和記憶體/資源洩漏,螺栓支援併發性,沒有模組,沒有名稱空間。錯誤處理可能相當繁瑣和冗長。當呼叫堆疊崩潰,或者攻擊性輸入操縱你的程式,很容易就產生一堆錯誤。

"When all else fails, read the instructions." 當其他辦法都失效時,請檢視說明! - L. Lasellio
它的瑕疵是非常非常有名的,這是一種優點。所有的語言和實現有陷阱和難題。C只是更坦率的告訴它。還有大量的靜態和執行時工具來幫你處理最常見的和危險的錯誤。世界上很多使用最廣泛和可靠的軟體是用C打造,這就是缺陷被誇大了的證據,這些瑕疵容易檢測和修復。
為了編寫couchbase,我們團隊大概花了2 + 人/月解決Erlang虛擬機器的問題。我們在Erlang的編譯器上花費了大量的時間和精力,卻仍然不確定到底發生了什麼,而結論是或許是我們的外掛的c語言程式碼出了什麼問題。我們想找出問題,然而卻找不到。最終我們確定這是Erlang的核心裡面有一個條件矛盾錯誤。這是我們唯一的成果。而太多的語言抽象掉了太多的東西,這無疑增加了類似我們遇到的困難。

最初,出於效能原因,我們決定用c重寫couchbase的程式碼,並且決定couchbase的幾個新的特性也用c來寫。令人驚異的是,顯然事實證明,c語言提供了對於程式的良好控制能力,而我們因此更容易快速找出程式的問題並進行除錯。長遠來看,c語言顯然具有良好的生產效率。

我總是告誡自己,我需要一個更加高效的可以替代c語言的東西。它只要可以修正程式裡面那寫毛糙的細節然後解決問題就可以了。但是從事實來看,不論是從語法、從語義、從工具或者從“自頂至底”的開發方法來看,沒有什麼可以值得我們為止付出努力。到現在為止,c語言毫無疑問的是最高效的語言,我認為短期內這不會有任何改變。

你可以在twitter上“推”我一下,然後就可以瞭解我對程式設計的一些看法以及couchbase的開發進度了~

C 語言高效得簡直不合理原文請看這裡

推薦文章