2016年5月6日 星期五

[嘴炮] - c++ 之電腦語言之爭

「通常來說, 學習新的程式語言要投注極大的智力、精力和時間, 特別是挑了一門很難學的語言, 只有程序员预期所学语言能够物有所值, 才會發動心力投入學習新的程式語言。」這是為什麼我只學習 c++ 的原因, 對於學習一個新的程式語言, 我會以很「嚴肅」的態度去評估, 而且光是 c++ 就可以耗上一輩子了, 如果別的程式語言沒特別高竿, 我就沒有動力去學習。

程序员永远的鸡血 - 编程语言之争》這種文章一向能引起程式員的「快感」, 很容易就可以發表自己的看法, 比起給出具體的程式碼容易多了。

裡頭介紹的幾篇有些有深度, 有些很平凡, 看起來好像說了很多, 實際思考後覺得好像什麼都沒說, 這也是「嘴炮」的快感之一。

我想練習一下這種「嘴炮」文章, 畢竟有深度的「嘴炮」文章也不是容易的, 那就來談談 c++ 吧!

我在 c++ 上花了很多時間, 事實上我只有學 c++ 這個語言而已, 在大學時代開始正式學習程式語言, 一開始是 pascal, 再來是 c, 然後我便自學 c++ 了。高中時自學組合語言就不說了, 太高估自己, 自學組合語言是一個失敗的例子, 我得到了一個「失敗的經驗」, 也不算是一無所獲。

很久以前 cgi 很流行用 perl, 我很堅持用 c++ 來寫 cgi, 大概是 perl 的 5 倍學習時間, 用 c/c++ 來寫 cgi 的資料很少, 那時候的我又不足以透過 cgi perl 的學習資料進而以 c/c++ 來改寫, 結果很久之後我才會用 c++ 寫 cgi, 而就是因為我不會用 c++ 寫 cgi, 大學課程上的某個資料庫作業我是用 delphi 完成的, 因為那個作業需要在 web 瀏覽器上展示這個功能, 那時候的 c++ builder 1.0 無法勝任這個工作。所以我在 windows 95 單機版寫了一個 c++ builder 1.0 的版本, web 版本則是用delphi 開發。表面上看起來是很無聊的堅持, 不過這就是我頑固的地方。

當時是看施威銘的書學 turbo c, 很不錯, 看完後覺得應該再來看 c++ (不知道為什麼有這種想法, 我應該是被 c++ 這名字所迷惑了, 這名字取得真好), 就把 turbo c++ 這本書看完了, 真是懷念 dos 時代那時候的簡單。

在那個時代, 一個人可以從底層玩到上層, 從顯示卡驅動程式到打造出一個有聲光動畫的遊戲。



再來就是很瘋狂的把侯捷老師的書都買了下來, 一本一本 K, 當然不是全部 K 完, k 完就真的成了王語焉, 當然還有葉秉哲博士的 the c++ programming language 中文版。我把 c++ primer 中文版和 the c++ programming language 中文版看完, c++ primer 中文版花了 2 年, 很久吧! the c++ programming language 中文版有進步, 花了半年, 閱讀時間少了許多, 你可能開始要佩服我, 覺得我 c++ 很厲害吧! 可是你有沒發現一件事情, 我完全沒提到我寫了什麼程式, 是的, 我只有看書, 沒有在寫程式, 這對於學習來說是個傷害, 而我對 c++ 也並不是很了解, 在 template 部份, 我幾乎是一無所知, 《知行一》這裡頭提到的 c++ 技巧, 我幾乎都不知道, 有些甚至看不懂, 看到這些作法我相當驚訝, 也覺得這實在是厲害, 但我在仔細思考一番後, 我不會這些技巧會怎麼樣嗎? 難道我就寫不出像樣的程式了嗎? 我喜歡 c++, 我學 c++, 我就一定要會這個那個嗎? 我不能只要 c 的那個部份就好了嗎?「那你怎麼不乾脆用 c 就好了?」「因為我無法抵抗 c++ 標準程式庫的誘惑」那個 std::vector, std::map 實在太好用了, 用過一次就忍不住了, 而 class, raii 也都是很容易就可以上手的特性, 不會耗費多少腦汁, 為什麼我不用呢?



這是 socket 的某個 function:
int getaddrinfo(const char *node, const char *service,
                       const struct addrinfo *hints,
                       struct addrinfo **res);

呼叫 getaddrinfo 之後, 還得記得要 freeaddrinfo(result), 而 res 本身又是個複雜的 linked list 資料結構, 有興趣可以參考 man page 的用法, 雖然難不倒你 (我騙你的, 這個 function 的用法絕對難倒很多人), 但用起來實在太複雜。

如果用 c++, 可以把這個 function 設計成這樣:

int getaddrinfo(const char *node, const char *service,
                       const struct addrinfo *hints,
                       vector &res);

用起來像這樣:

std::vector<struct addrinfo> res; 
getaddrinfo(..., res);

for (int i=0 ; i < res.size() ; ++i)
{
}

不用去記得要呼叫 freeaddrinfo(result), 而程式一樣有著高效率。用 linked list 和 vector 在本質上沒有什麼勝負之爭。

以下是這兩個差異的範例程式碼:
https://github.com/descent/progs/blob/master/ipv6/host_to_ip.c
https://github.com/descent/progs/blob/master/ipv6/host_to_ip.cpp

你喜歡用哪個?



為什麼我堅持要學 c++, 因為我知道我要走的方向是系統程式語言的路, 尤其是我最近愛上寫 bare-metal 的程式, 這領域的選擇不多, c, c++, 組合語言這些吧, 若有遺漏, 請告知我, 感謝。如果 c++ 真的加入了 gc, 我很煩惱我是不是會放棄這門語言, 以我的認知, 加入了 gc, 基本上就與系統程式語言無關了, rust 甚至拿掉了 gc, 還拿這個打著自己是系統語言。


c++ 竟然想要加入 gc, c++ 一旦加入 gc, 我認為大概就和 java 在同一個層級上了, 這是讓我覺得自廢武功的特性, 怎麼加入 gc 又保有系統語言的能力, 交給 Bjarne Stroustrup 去煩惱了。

我不會去比較 java 和 c++, java 無法提供我要做的功能/效能, 但是 c++ 一樣可以完成 java 能完成的程式, 我沒有必要去花時間再學習能做一樣事情的 java。你能用 java 寫出 c++ 標準程式庫嗎? 甚是連 c++ 自己也無法完成 c++ 標準程式庫, 有些還需要出動組合語言。我需要這部份的能力, 只有 c/c++/組合語言可以選擇了。而 c++ 卻可以寫出 jvm, 這算是兩個語言很大的不同。

jnode 是一個用 java + asm 完成的 os, 讓我大呼驚訝, 真不知道是怎麼做到的? 也許我該改變我對 java 的看法。

我已經知道了, 作者只使用了組合語言和 java, 用組合語言打造了 java 虛擬機器, 然後就可以執行 java 的 class。

http://www.jnode.org/node/175

再來談談快速的開發, 我曾經在某篇文章看到 ruby 只要用 gem install rails 再花 15 分鐘就可以打造一個 blog, 很有成就感吧!

  • 不過你不會想知道這裡發生了什麼事情嗎?
  • 不會想搞懂這些經過嗎?
  • 你認為沒有那些背景知識就可以駕馭 rails 了嗎?
  • 只要知道 rails 怎麼寫就夠了嗎?

如果你要搞懂這些, 覺對不可能只要 15 分鐘吧! 《給網站初學者的建議:用 Ruby on Rails 非常辛苦,用 PHP 非常舒服》這篇驗證了我的想法, ror 之薪水高的背後原因是因為那些人程度本來就很好, 就算用別的語言, 也是高薪的那塊族群。這是那些開課的人不說的祕密。

速食文化令人難以抵擋, 但每個程式員的屬性不同, 你要走哪方面呢? 我知道我不是屬於這種「速度快」的, 如果是我, 我會把每一步搞懂, 但是這樣我就輸給那些速度快的開發人員了, 這兩種屬性哪個好呢? 沒什麼好壞, 就是「選擇」而以。你要快, 你就是犧牲了某些東西; 我要搞清楚事情來龍去脈, 也是要犧牲某些東西。

我喜歡慢慢、仔細的學習方式, 所有學問都是這樣慢慢煉成的, 就像太上老君的煉丹爐, 其實我不相信有那個專業可以快速學成, 那太侮辱那個專業了。寫作、烘焙、新聞採訪 (厄 ... 這例子可能不太好, 你知道的)、就算是打掃都有其專業的地方, 讓我們向這些專業人員致敬。

c++, c++11 都很有多的特性, 但程式員沒有一定要把所有特性全部學會才能寫程式, 我最常用到就是 if/else, while, function, raii, 標準程式庫的容器, 什麼 lambda, template, 我並不是很理解, 我把重點擺在寫出程式, 而不是用這個程式語言的什麼厲害的特性。

而且一旦依賴了某個程式語言的特性, 那就像是吃了鴉片一樣, 你可能會沉迷於這樣的使用方式, 若一旦需要使用沒有這樣能力的語言, 那就樣鴉片癮一樣, 會很痛苦。我並不是說這是壞處, 而是一個「選擇」。

舉個例子: c++ 的 stl 很好用, 像 std::map 這樣好用的資料結構並不算很好寫, 一旦選擇用 c, 就要自己想辦法寫出類似的東西, 這時候資料結構重要派的人就會說了:「看吧! 資料結構很重要, 要好好學。」好在這樣的基礎建設大都可找到 library 來使用, 但合不合用那就不一定了。像我對於 c string 系列的 function 就很不熟, 我只有學 c++, 都是用 std::string, 方便性都比 c string 好用不少。我覺得對於練功來說不是好事情, c string 可以讓程式員對於指標操作有很好的練習, 我跳過這個練習了。

c++ 討論區上的神奇技巧, 我看的目瞪口呆, 因為我一個都不會, 但我並不覺得輸人一大截, 每個人著重的地方不同罷了。

再來的《續篇》我就不會展示這麼好的修養了, 我要好好反駁講 c++ 壞話的文章。

有人說學習 c 只要一本 the c programming language 就夠了, 但我可以很輕易的就舉出幾本也是很棒的 c 學習書籍:
  • C程序设计的抽象思维
  • C语言程序设计:现代方法(第2版)
  • C语言接口与实现:创建可重用软件的技术
  • expert c programming (C 专家编程)
  • c trap and pitfalls (C 陷阱与缺陷)
這些都是十年以上的書籍, 經得起考驗, 請放心閱讀。 之前沒用心在學 c (我是學 c++), 現在補上。

functional language 重出江湖, 成為目前的顯學, currying, monad, lambda ... 一堆名詞, 頗有 2000 左右 OOP 大軍的味道, 封裝、繼承、多型 ... 但我覺得 fp 思維太燒腦袋, 能上手的人僅僅是少數。OOP 似乎變成落水狗, 雖然不到人人喊打, 但也失去了喊水會結凍的霸主地位。

ref:

20170712 補充:
c++17 要出來了, 看到了很多不懂的新特性, 現在我會選擇, 不再盲目的跟上這些東西, 把心力花在自己覺得值得的地方。

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。