[重新理解 C++] 開篇


因為存在一些誤解

很多人學習 C/C++ 是從學校教授或者公司前輩、legacy code 上學習。
這些學習方式一定程度上給初學者帶來一些偏見
這些偏見某種程度上讓初學者更快的能使用一些複雜的概念
然而也一定程度上限制了他們思考的深度,以至於無法活用許多C++的特性,
而寫出 C like 或 Java like 的 C++ code,
有時甚至會產生一些錯誤的觀念,最終使初學者寫出有問題的代碼而渾然不知。

這個系列文一定程度上想試圖解決這個問題。

所以教授跟公司前輩都是雷包?

非也,雷的其實是體制
和一定程度上還是菜鳥的你。

C++ 是極其複雜、抽象的語言
對學校老師來說,他必須在一學年或甚至一學期內讓你學會 C++ (或其他高階語言)。
此時的你甚至是還不會 loop 的小白。
這其實是相當困難的,所以教學上只能用很具體的概念去呈現,
比如畫 memory layout, pointer
去解釋那些複雜的概念。
然而這些圖只是一種近似,但是你可能以為這就是全貌
結果就錯了。

更甚者丟一本 C++ Primer, 然後跟你說所有寶藏都在那裏。
你就去成為海賊王吧!

公司前輩也是類似的道理,很多公司的新人引導 KPI 是會記在公司前輩上的。
而同時這位前輩還有自己的產能要顧,他也只能囫圇吞棗的教。

沒辦法被注意到的寶藏

很多人都非常推崇 C++ Primer 這本書,
我也認為這本書非常好,但是這是一本資訊量爆炸的書
性質跟字典類似

你會去讀字典嗎?

我曾經遇過一些熟讀 Primer的人遇到一些基本問題還是卡住,比如
我在以前公司的新人,遇到 compiler 回報 multiple definition error 然後就卡了。
我心想他不是號稱把 Primer 都讀完了嗎,怎麼會不知道 ODR(one definition rule) 呢?
然後我把他的書拿來翻了翻,我發現他確實有讀過這部分,因為有一些筆記註解的痕跡在。
事後我問他一些書上的知識,他也確實都知道。
然而 Primer 整本書的資訊量像海一樣深,很多人把重點放在 class, data type
那些有 example code, 可以馬上操作的語言特性,
於是像 ODR 這類必須從錯誤中學習的部分就被輕忽掉了。
所以這也不怪他了,這不是讀書就能解決的問題

這說明什麼呢?
讀萬卷書不如寫萬行 code......?

實作盲點

很多人在學習高階語言經常會寫一個小 case,以 編譯器給過執行期結果 來當作一種「正確」的標準。

然而這是錯的。

語言標準有其極限。隨著時間技術演進大部份的語言標準都會出現漏洞
這些漏洞又稱為未定義行為(undefined behavior),意思就是編譯器給過了,
執行期也跑出結果了,但是對其結果語言標準不給予任何保證。

高階語言必須保證原始碼是平台無關的(platform independent)
意思就是一模一樣的代碼其執行結果不管在任何平台、機器都必須一樣。

然而有的語法設計早期可能是少考慮了一些情境,也有可能是當時就是不存在某種機器架構,
結果導致今天該語法無論如何都不能起到這種保證,語言標準最終只能在這些議題上選擇放棄。

舉個例子:C/C++ union 語法
可能以前學校老師會這樣教:

union {
    int i;
    float f;
} data;
data.f = 3.14159;
printf("%d", data.i); // 得到 3.14159 的 integer reinterpret cast (或者俗稱 serialization)

然後進一步可能輸出二進位或16進位來闡述 IEEE754 的設計云云。

然而這份代碼是有問題,因為 C/C++ 皆未對浮點數的存儲方式計算方法的實作給出規範。
C 的設計甚至早於 IEEE754
每台機器可能對於浮點數運算的暫存器、二進位存儲方式、各種運算的實作都有所不同,
更甚者可能連 int 都不是用二的補數設計,所以 data.i 的內容其實沒有任何保證。

可因為當今世上最唾手可得的機器都是 x86, AMD64 架構,可能隨便實驗結果都是一樣的結果。
於是就把這個半對的事實當作真理,寫了很多不牢靠、平台相依的代碼。

盲目的信任實作得到的經驗其實也不完全靠譜。
所以 code 要寫,書也還是要讀.....

可是主管教我這樣寫,你比他厲害?

非也,他可能是正確的。
就如同上面說的,一切不確定性來自於平台。
然而對於企業來說,產品要支援什麼平台,code 跑在什麼機器上都是已知確定的。
如果企業主力產品就是晶片,FPU 就是用 IEEE 754 實作
而你是個寫 driver 的 SE,你還鼓吹大家別用 union 做 reinterpret cast。

那不叫明智,那叫矯情。

那什麼才是對的......

就我個人的經驗,programming 不存在萬物皆通的道理。
但凡意圖歸納「法則」的書、人,最終都會在某個情境被推翻
或者你用過之後發現其實改善非常有限,但製造的缺陷卻更多

在你還是超級初學者的時候,
知曉「法則」是一種你用過功的證明而不代表你真的有某種可以取代經驗的知識,
你在一定程度比較不容易給經驗老到的人製造麻煩,
然而你也要清楚被現實捶打過的樣子其實跟書上是相去甚遠的。

只有不斷在各種你發現不對勁的時候思考,
而且要常常思考技術以外的問題你才會找到屬於你的正解。

最後

這個系列其實不適合給超級初學者看,最好應該寫過兩三萬行代碼的人來看會最有幫助。
如果你離職場還非常遠,比如沒做過任何專案,那是不太建議看這個系列的文章
(哈,此人用代碼行數衡量實力?非也,這是有特殊意義的,改日再針對代碼行數的意義做個詳細的討論)
另外這個系列的更新頻率目前設定是半年一篇,非常緩慢。
因為本人上班之餘大部分時間也要拿來寫 side project, 實在沒有這麼多時間寫文......

2021/2/28 author by John Chang

#C++ #軟體工程 #雜談







Related Posts

Code Runner 亂碼問題

Code Runner 亂碼問題

Kotlin 練功場 - Android 組

Kotlin 練功場 - Android 組

Day 67 - 留言板 Part 3

Day 67 - 留言板 Part 3






Comments