>> 有偏見(jiàn)的永遠(yuǎn)只是個(gè)體,而不是群體。作者加了后面那句,無(wú)疑證明有偏見(jiàn)的不是C/C++程序員,而正是他自己。
學(xué)生時(shí)代,我也曾醉心于C/C++,但時(shí)至今日,始終無(wú)法寫(xiě)出無(wú)懈可擊的C++代碼,所以我始終認(rèn)為我不會(huì)C/C++。這些年,我一直在尋找編寫(xiě)C++代碼的最佳模式。但是,老實(shí)說(shuō),我還沒(méi)有見(jiàn)到過(guò)哪個(gè)稱得上高手的C++程序員,也沒(méi)有見(jiàn)到過(guò)寫(xiě)得Very good的C/C++代碼。C/C++代碼總是丑陋不堪,BUG叢生!
>> 這段話更加荒謬了。沒(méi)見(jiàn)過(guò)優(yōu)秀的C/C++代碼? C++標(biāo)準(zhǔn)庫(kù)(STL)如此優(yōu)雅。況且,有那么多經(jīng)典的C/C++開(kāi)源作品,以及無(wú)意之中泄漏的Windows NT核心源碼,哪一樣不是絕世之作?我為作者淺陋感到難過(guò)。
我用C語(yǔ)言編程已經(jīng)超過(guò)20年了。我寫(xiě)過(guò)C語(yǔ)言的編譯器、C語(yǔ)言的調(diào)試器、用C開(kāi)發(fā)的其他語(yǔ)言、游戲、客戶端程序和服務(wù)器程序,你說(shuō)吧!還有什么是我沒(méi)寫(xiě)過(guò)的。還有我的書(shū)架上充斥著折了角的K&R和Steele的書(shū)。我太了解C語(yǔ)言了,但是,我討厭他。十分討厭!
當(dāng)我讀到一篇博客,題目是"為什么每個(gè)程序員都應(yīng)該學(xué)習(xí)C語(yǔ)言?"時(shí),我真是雞皮疙瘩滿地。如果你真的是個(gè)專業(yè)的程序員的話,你肯定覺(jué)得這是個(gè)天大的笑話,盡管作者的本意也許不是這樣的。這篇反駁的文章有點(diǎn)意思,但是還是沒(méi)有抓住本質(zhì)。所以我展開(kāi)了說(shuō)一下。有以下5個(gè)原因來(lái)說(shuō)明,為什么那些會(huì)C語(yǔ)言,并且使用C語(yǔ)言的程序員,現(xiàn)在不但應(yīng)該去用別的語(yǔ)言,而且應(yīng)該忘記他們學(xué)習(xí)C語(yǔ)言過(guò)程中的那些煩人的東西。
1、內(nèi)存分配
僅僅關(guān)于這一點(diǎn)我就能寫(xiě)整整一篇文章了,也許能寫(xiě)一本書(shū),甚至還有可能寫(xiě)出能夠塞滿圖書(shū)館技術(shù)書(shū)籍那塊,那么多的內(nèi)容。內(nèi)存分配和存儲(chǔ)單元分配的存在確確實(shí)實(shí)是個(gè)*煩。你要不就是分配太少的內(nèi)存不夠用,要不就是分配了太多內(nèi)存浪費(fèi)掉。這里的問(wèn)題就是:怎么把它初始化為零呢?還是干脆就不初始化它。但最撓頭的步驟還是釋放內(nèi)存。所有已有的工具包都會(huì)幫助你確認(rèn),你是否已經(jīng)釋放了之前分配的每一位的內(nèi)存,在釋放完之后是否永遠(yuǎn)不使用它,并且會(huì)阻止你,永遠(yuǎn)不要釋放它第兩次。更嚴(yán)重的是,分配內(nèi)存和釋放內(nèi)存在C語(yǔ)言中都是很慢的,非常慢。使用內(nèi)存分配時(shí),要考慮的各種特殊情況,我真是連想都不愿意去想,只要問(wèn)題(對(duì)象)的大小合適,我更愿意使用棧空間或者事先分配的結(jié)構(gòu)空間。如果這么做的話,我就有更值得煩惱的事了。話說(shuō)回來(lái),發(fā)明垃圾處理器那人真應(yīng)該得諾貝爾獎(jiǎng)。
>> 內(nèi)存管理是程序設(shè)計(jì)中最經(jīng)典的話題。GC無(wú)疑是內(nèi)存管理一個(gè)偉大的變革,但是我只是把它看作內(nèi)存管理的一個(gè)解決方案,而認(rèn)為不是唯一的解決方案。比GC更加優(yōu)雅的方案不見(jiàn)得沒(méi)有。我比較傾向于在特定的情況下選擇合適的內(nèi)存管理方案,而不是沒(méi)有任何選擇的余地,而這正是C/C++的偉大之處。 所有那些GC語(yǔ)言(如Java、C#等)均把這個(gè)解決方案強(qiáng)加給程序員,這一定程度上來(lái)說(shuō)減輕了程序員的負(fù)擔(dān),但是也同時(shí)約束了程序員的主觀能動(dòng)性。"分配內(nèi)存和釋放內(nèi)存在C語(yǔ)言中都是很慢的"?不知道作者從哪里獲得的結(jié)論。
2、多線程
我過(guò)去是喜歡C語(yǔ)言的,真的。直到我開(kāi)始用C開(kāi)發(fā)并維護(hù)多線程的服務(wù)器。在為連接相沖突的線程保護(hù)數(shù)據(jù)方面,C語(yǔ)言沒(méi)有為程序員提供那怕一點(diǎn)點(diǎn)的幫助。你在使用單線程的日子里獲得的每一個(gè)直覺(jué)、經(jīng)驗(yàn),用在多線程的時(shí)候都是錯(cuò)誤的。至少JAVA有表示同步的關(guān)鍵字和備有證明文件(但是是個(gè)很奇怪的文件)的記憶體,但即使是這樣,除非你使用新的javax.concurrent,否則也只能在那些巨大的平行擺放的機(jī)器們面前崩潰?;氐紺語(yǔ)言上:在模擬生產(chǎn)的環(huán)境下,堅(jiān)持一個(gè)星期在數(shù)據(jù)中心調(diào)試一個(gè)死鎖(這事真的發(fā)生過(guò))。而JAVA卻只需要Ctrl+Break!天哪!!!
>> C/C++語(yǔ)言本身確實(shí)沒(méi)有太多MultiThead的支持,這種情況在C++0x出來(lái)后可望改變。但是,請(qǐng)記住C/C++永遠(yuǎn)傾向于你使用成熟的庫(kù)來(lái)解決問(wèn)題。
3、指針
指針太難以控制了,太陰險(xiǎn)了;我甚至沒(méi)有委婉一點(diǎn)的方式去形容它。我生命中每年都有幾個(gè)月被用來(lái)調(diào)試那些奇怪的指針問(wèn)題。我過(guò)去常常努力獲取所有的訣竅,比方說(shuō)難以理解的構(gòu)成符、聯(lián)合體和偏移量,以及重用最后兩位做標(biāo)記,還有所有其他的訣竅。但我發(fā)現(xiàn)這么做根本不值得。其他語(yǔ)言的靜態(tài)引用就可以解決了。
>> 指針是C/C++過(guò)于靈活的體現(xiàn)。使用指針的代碼可以寫(xiě)得很丑陋,但一樣可以很優(yōu)雅。——這一點(diǎn)上用何種語(yǔ)言不會(huì)有區(qū)別。我相信,可以寫(xiě)出優(yōu)雅的Java代碼,那么也一定可以寫(xiě)出同樣優(yōu)雅的C/C++代碼。而反之則未必(因?yàn)橛行〤++某些范式是Java所不能支持的)。C/C++語(yǔ)言中的選擇太多,這的確是令人困惑的,但不見(jiàn)得是劣勢(shì)。我對(duì)C/C++程序員的建議是,多了解和使用C++標(biāo)準(zhǔn)庫(kù),而不是過(guò)于糾纏指針相關(guān)的細(xì)節(jié)。
4、過(guò)早的優(yōu)化
說(shuō)到訣竅,你是否曾經(jīng)浪費(fèi)腦細(xì)胞去研究究竟*p++是不是比p[i]快?你是否曾經(jīng)花時(shí)間去試著做點(diǎn)變化來(lái)代替乘法,或者去嘗試使循環(huán)中的倒置運(yùn)行更快的方法?還在為傳遞一個(gè)參數(shù)的速度和反對(duì)添加結(jié)構(gòu),并且傳遞它的速度一樣而苦惱不已?停吧!算法是速度的關(guān)鍵,程序員的水平?jīng)Q定了他會(huì)使用那些算法。知道這一點(diǎn)能讓你的程序更好,更快一點(diǎn)并且讓你的腦袋少扭幾個(gè)筋。好吧,有一些例子也許可以這樣做的……不,你就別那么做就行了!
>> 算法優(yōu)化是程序設(shè)計(jì)的關(guān)鍵。但是通常情況下,所有語(yǔ)言(包括C/C++)的程序員研究的是關(guān)鍵路徑的優(yōu)化。研究*p++是不是比p[i]快?我相信這是標(biāo)準(zhǔn)庫(kù)的實(shí)現(xiàn)者要考慮的事情。所不同的是,C/C++程序員也可以和標(biāo)準(zhǔn)庫(kù)的作者一樣去考慮這些細(xì)節(jié),而其他語(yǔ)言的程序員被剝奪了這個(gè)權(quán)利。
說(shuō)到優(yōu)化,話題就多了。我曾經(jīng)向C#的Dictionary中插入了1億條整數(shù)(從1萬(wàn)多個(gè)文本文件中讀入),結(jié)果發(fā)現(xiàn)程序運(yùn)行了整整一個(gè)下午仍然沒(méi)有完成。而我改用C++的std::map,20分鐘就搞定了。再試試對(duì)50萬(wàn)條自定義的結(jié)構(gòu)體數(shù)據(jù)進(jìn)行排序,我相信你和我一樣,會(huì)深深喜歡上C++的的高效而優(yōu)雅。
5、測(cè)試
你最喜歡的C的單元測(cè)試的工具是哪個(gè)?嗯…一個(gè)也想不到?單元測(cè)試一定是一點(diǎn)也不重要,是吧?或者是太麻煩了,很難跟上進(jìn)度,浪費(fèi)時(shí)間。你可以把這個(gè)時(shí)間用到更加有用的事情上,讓它只占用工作時(shí)間的1%,那還比較合適?;蛘咴跀?shù)據(jù)中心,通過(guò)優(yōu)化的沒(méi)有標(biāo)記的圖形來(lái)調(diào)試這個(gè)僅僅由100個(gè)同時(shí)在線使用者引起的問(wèn)題。
>> C++的測(cè)試工具,作者居然一個(gè)都想不到,我只能猜想可能他是比較喜歡自己制造輪子的那一類。和JUnit對(duì)應(yīng)的CppUnit,難道也想不到?提起CppUnit,我以前用它進(jìn)行單元測(cè)試,但從實(shí)現(xiàn)架構(gòu)上說(shuō),我認(rèn)為它繼承了Java代碼的臃腫。我在WINX中提供了一個(gè)Mini版本的CppUnit,代碼量大概只有幾百行,功能絕不比CppUnit弱。(要了解WINX,請(qǐng)看這里)。
我本來(lái)應(yīng)該繼續(xù)再說(shuō)一些原因的,但是5個(gè)現(xiàn)在就足夠了;說(shuō)完這些,現(xiàn)在感覺(jué)好點(diǎn)了。C以前是非常棒的…那是在1984年的時(shí)候。直到今天,那些用C寫(xiě)的新代碼都讓我感到驚喜…如果你讓我比較的話,我覺(jué)得C++只是比C稍微好點(diǎn)。如果你想要學(xué)些老一點(diǎn)的語(yǔ)言,不妨嘗試Forth,List,或者APL。這些老式的語(yǔ)言起碼能教會(huì)你,用不同的而且優(yōu)雅的方式去思考你的程序。
>> 新生的語(yǔ)言,必然會(huì)在吸收舊的語(yǔ)言上基礎(chǔ)上進(jìn)行改進(jìn)??匆粋€(gè)語(yǔ)言的生命力,并不在于看它某些地方存在的不足。事物會(huì)發(fā)展,并趨于完善。相信C++0x出來(lái)后,C/C++語(yǔ)言又將獲得新的生命力。單看Java、C#等幾個(gè)新一代的語(yǔ)言,其中有如此多的C++烙印,就證明了C/C++的影響是巨大的。動(dòng)不動(dòng)說(shuō)一門語(yǔ)言死了,是一種淺薄。
申請(qǐng)創(chuàng)業(yè)報(bào)道,分享創(chuàng)業(yè)好點(diǎn)子。點(diǎn)擊此處,共同探討創(chuàng)業(yè)新機(jī)遇!