這時代的 C 語言還有什麼用處呢?

「在現在這個時代,學習 C 語言還有什麼用處呢?」 這是現在從許多年輕學子身上能夠聽到的疑問,當然這問題也同樣能套用到 C++ 語言上。 這裡我就以個人從業多年的學習與理解,分享我對此問題的解讀, 告訴你 C (以及順便一提 C++)到底還有什麼樣的核心價值?

其實會比較深刻產生如標題這樣問題的應該大多是正在學習 C 語言的新手, 可能是大學理工科的學生,可能是國高中第一次接觸程式語言的學生。 埋首圍繞在程式語法結構的規則,正在學習如何用程式語言列印九九乘法表這樣的基礎練習中, 翻看課本講義直到整篇結束大概都是這些東西, 實在很難理解看起來就這樣能耐的東西,如何能夠演變成自己電腦上那個畫面炫麗的遊戲軟體? 不過這個問題並不是我本次關注的重點。 除了學生之外大概還有另外一群人, 他們已經對程式語言具有一定的熟悉度和使用熟練度,至少已經脫離了學習痛苦期的深淵, 已經能夠使用 C/C++ 獨立完成作業、小品,或基於某項具體功能的軟體程式製做。 這些人對於程式語言的理解熟悉使他們的問題進入了另一個層次, 也許不再懷疑這種基礎語法裡面只有看上去好像很簡單的一些功能的語言如何能夠製做出一個具體能用的程式。 但是轉頭再看看其它更加現代先進的程式語言如 Java、Python 等後起之秀, 它們使用起來可更加簡單方便且功能更加強大豐富得多, 相比之下 C 語言(以及 C++)雖然也不是辦不到這些事,但是明顯感覺並沒有優勢。 而這個問題就是本篇所要探討的主要議題, 也就是 C 語言在現代被大量後起之秀環伺包圍的環境下,究竟還有什麼價值? 在什麼用途上它能夠比其它的程式語言更加具有優勢嗎?

最後再提醒一點,這裡我探討的重點是 C 語言本身的價值和優勢, 至於應不應該、適不適合作為新手入門的第一個語言……, 那是另一個問題了! 另外我在後面也要順帶探討一點對於 C++ 的評判。 雖然嚴格意義上來說 C++ 與 C 是兩種獨立的程式語言, 但是由於一些奇妙的因素使它們之間常常糾纏在一起,通常熟悉其中一個的人往往也很難得不熟悉另一個, 甚至不乏有些程序員不能夠意識區分這兩者。 因為它倆的相依相生,並且也正好我對它們都有一定的熟練度,藉此機會就一起分析探討一番了。

C 語言的價值與優勢

單純、精簡、輕便、高效

C 語言大概是現存的所有(高階)程式語言裡面最單純、最簡單的了。 不過注意啊,這裡說的是語言本身語法、結構和邏輯簡單單純,不是說你學起來很簡單啊! 這就好像是同樣雕刻一個大理石雕像, 一個雕刻師拿了 CNC 車床外加五軸連動機械手臂、和五十個不同的切刀頭來進行工作, 另一個老師傅卻只拿了一組六支雕刻刀加一把鎚子就完成了工作。 這組雕刻刀簡單是真簡單,單純是真單純,能完工是真能完工,但不表示你學起它來也是如此簡單。 這就是我說 C 語言簡單的真意。

C 語言的設計非常精簡精煉(當然這是指對於機器設備,而不是對於使用它的人), 並減少所有一切不必要的行為與工作,只以忠實完成程式設計師所明確交辦的工作為主, 至於多餘的則當作不存在。 這樣的語言哲學賦與 C 語言擁有與底層設備溝通並進行控制的能力, 因此那些驅動程式、作業系統核心、以及硬體設備上的機載程式等等, 往往必須由 C 語言來進行開發。 加上它工作單純並且不自作聰明執行額外工作的特點,是 C 語言成為高效率語言的基礎要素, 而這些特性卻是其它類型高階語言所難以俱備並與之比擬的獨特優勢。 因此那些非常講究效能的用途如大量資料的快速運算處理, 或者運算資源匱乏的用途如嵌入式設備程式等, 或者需要在系統底層運作、或與硬體溝通交互的驅動程式、底層模組與程式庫等, 就都喜歡以 C 語言作為主要的開發語言。

這裡可能有些人會不服氣,因為要比底層細部控制的話, 組合語言(assembly)可比 C 語言更加瑣碎細緻並且接近硬體。 話是這麼說沒錯,不過組合語言已經脫離了高階語言的範疇,不屬於高階語言了。 因此這裡還得補充一個註腳: C 語言是在高階語言的範圍裡面最接近硬體邏輯與控制能力的語言, C 語言是最低階的高階語言!

當然好與壞是相伴的,否則 C 語言的這些特性這麼優良的話, 又為什麼讓更新穎的當代語言紛紛拋棄許多比它們更古老的前輩所擁有的能力呢? C 語言貼近硬體、貼近計算機底層,於是讓光是一個整數就有各種長度不一、區分有號無號的類型, 可能還得區分堆疊空間、堆棧空間、還是全域空間, 能夠充份發揮硬體最優配置是真,但是能讓使用者昏頭踩坑也是真。 讓使用者直接操作記憶體地址賦與了完整的記憶體資料存取控制能力,卻也成為地址違規存取和堆疊洩漏發生的溫床; 能讓使用者自由的索取與歸還記憶體資源,使程式可以在設計者的規劃之下最妥善高效的操作大量資料, 卻也成為記憶體洩漏的最直接來源。 使用者若沒有要求則不會對任何空間進行初始化行為,成為它效率高的其中一項因素, 卻也導致各種未初始化引用的神奇問題,特別經常容易讓初學者摸不著頭腦。 如果要細細講解的話其實還有很多可以提,但是這一切其實都在告訴我們一件事, C 語言的優點其實往往是背負著相對應的代價而來的。 這些便是那些比它更加新生的語言之所以沒有想要「擁有」這些優點的原因, 當然同樣也就是 C 語言在適當的使用情境下之所以比其它語言更加優異的原因。

教育與學習

C 語言還特別適合作為學習用途的程式語言, 但請注意我這裡說的教育是有針對性的,而不一定是指廣泛情況下的教育用途。 C 語言的語法本身非常簡單單純,這點前面已經說過了, 如果暫且不管熟練精湛程度而只看僅僅能「會」的話, 雕刻刀顯然是比五軸連動 CNC 車床更加容易入門學會的東西, 可能也因此成為過往許多學校教授學生入門程式語言的選擇。

C 語言的瑣碎、不多事這項特點在有些地方是缺點, 但在學習階段卻反而具有強迫學生養成相對良好習慣的動力。 至少要了記憶體得記得還回去,並且變數不設初始值、以及各種違規操作等, 都很有機會在學習的階段就先爆發出來,想要不重視也不容易。 需要使用者對各種東西進行細微的操作這點, 更比其它語言更能夠讓學生在學習的階段一起感受體會到計算機的底層邏輯和運作原理, 如理解記憶體與位址、堆疊空間、地址對齊、和呼叫與執行流程等等。

不過很明顯以上這些所謂優點是對於計算機相關科系學生的情況來說的, 如果學習程式語言的目的有意要鑽研了解計算機相關知識並累積基礎的話, 那麼 C 語言更是無法逃避的一個知識領域,必須得學,最好從一開始就學。 至於非計算機相關科系,也不打算往這個方向發展, 學習程式語言只是為了執行一些簡單工作的目的,或者作為興趣啟蒙的話, 那麼這就是另一個話題了; C 語言不一定適合作為廣泛情況下給人的第一個學習入門語言, 甚至它的瑣碎枯燥可能還會起到反效果!

作為軟體協作介面

C 語言在現代其實還有一個可能比較少人注意到但卻非常重要的價值, 那就是作為軟體模組與模組之間的協作介面。

這是什麼意思呢?軟體程式往往都是被設計成許多不同的區塊來共同協同工作的, 就好像是公司的不同部門、機關的不同處室單位、園區的不同廠房等。 不同的部門即軟體模組各自專心負責自己的工作與任務, 然後用某種連繫方式將這些部門給連繫起來,共同構成一個系統的一整體, 於是乎,顯然就需要一種能夠讓各模塊共同使用的溝通交流介面。 關於這個問題,其實幾乎所有的程式語言都提供了這種機制, 然而這些機制大多都僅限於在使用同一種程式語言(甚至還得是同一個版本的編譯器)所寫成的模組之間。 那麼問題就來了,現代其實存在非常多種不同的程式語言,彼此各有擅長和不擅長的地方, 理想上最佳的做法是使用最恰當的語言去實現最適合的軟體模組,然後再把它們給連繫起來; 但是,這些由完全不同的程式語言所製做的模組該怎麼樣統一交換資料並協同工作呢? 這時候,C 語言就是那個最為適合的語言了!

有賴於 C 語言本身的簡潔單純並且缺少隱晦隱藏的各種奇妙機制, 本來在現代各種先進語言面前應該是某種缺點, 然而這些缺點卻陰差陽錯的在這個時代成為所有程式語言之間的最小滿足標準, 成為用來定義軟體介面與界定彼此邊界的規格定義最佳語言, 成為讓不同程式語言之間可以互相協同工作的中介者。 對於那些學過不只一種程式語言的程式人,可以試著回想看看, 是不是幾乎所有的程式語言都可以有辦法呼叫那些由 C 語言所實現的程式庫? 對於大部份偏向系統面的程式語言(至於偏向使用者應用端的可能就沒有了), 甚至還能提供某些方式讓你製做出符合 C 語言規格的程式庫介面, 讓其它由 C 語言寫成的應用可以呼叫你的程式庫(當然也包含那些能夠呼叫 C 語言程式庫的其它語言); 至於脫離了 C 語言之外,好像能夠提供不同語言直接互相溝通呼叫的介面就付之闕如了?!

這就是 C 語言在當代,除了用來實現底層驅動、以及極度講求高效能和低消耗的領域之外, 可能更加關鍵重要的角色地位了,那就是作為千萬種各有所長的程式語言之間的溝通橋樑。 學習和了解 C 語言的更大用處可能不是在許多人不知道一輩子有沒有機會接觸的系統軟體開發, 而是在適當的時機可以讓你真正放開單一語言的束縛,可以放手使用最擅長的語言做它最擅長的事, 並且還能將它們給凝聚協調起來。

C++ 的價值與地位

說了 C,就免不了也要提一下 C++。 說實在的,在這個時代,與 C 語言仍然掌握核心價值不同,C++ 的位置算是有些尷尬!

嚴格說起來,C 與 C++ 完全就是兩個不同的程式語言,理論上應該是完全獨立的, 然而實際上這兩個語言之間又存在著千絲萬縷的連繫,往往斷不了彼此的牽掛。 C++ 在誕生之初就將自己定位為 C 語言的超級擴充,號稱為一個「更好的 C」、「更加功能豐富的 C」。 除了發明 C++ 自己的語法功能之外還延伸包容支援所有的 C 語法功能, 並且在往後數十年各自的規格更新之中,二者也往往兼容彼此的新規格, 因此使得 C 與 C++ 成為形影不離的兄弟。

然而理想很美好,現實卻不照著想法走。 理想中 C++ 包含了 C 的一切功能,並且給的更多,然而這並沒有讓 C++ 完全吃掉 C 語言的領地, 事實上 C++ 最大的缺點大多源自於它一開始所強調的優勢與豐富。

複雜、難學、不一定可靠

C++ 太過複雜龐大,是目前為止世界上公認最複雜的程式語言。 有一句網路笑話是這麼說的: 「那些說自己精通 C 語言的人有可能真的很精通;但那些說自己精通 C++ 語言的人,肯定不精通!」 這句網路笑話就非常生動的表現了 C++ 的複雜, 事實上往往愈是學習熟悉 C++ 的人,往往愈學愈不敢說自己精通(作者我自己也是愈學愈不敢)。

C++ 過於龐大複雜,首當其衝的就是對生手的學習和上手難度極大; 但這其實只是最不重要的一個缺點,畢竟只要有價值, 世界上學習難度更大更困難更複雜的事情也不乏有人前仆後繼去學習。 它的過度複雜,使得語言的行為有時候很難弄得清楚; 或者就算有人能夠弄清楚,還有些部份很難定義清楚; 或者就算能夠定義,也很難保證編譯器的實現在這麼複雜晦瑟的規格之下能夠完全沒有意料之外的錯誤! 這一切使得它的可靠性受到些許質疑,特別是在那些極度強調可靠性的應用領域裡更顯得令人不安!

環境資源要求

撇除這些問題之外,C++ 往往也攻佔不了那些原本由 C 語言所佔領的領域, 雖然 C++ 完全相容 C 並且還給的更多, 然而 C++ 的龐大直接使得它的運行時庫硬生生比 C 時庫膨脹近四倍(以 GCC 為例), 偏偏那些原本 C 語言所生存的領地大多都是運算資源與儲存資源拮据的環境! 此外 C++ 的許多基礎功能其實脫不開一個完善的系統服務在背後撐腰,比如說例外機制、RTTI 等, 而在 C 語言所生存的地方卻往往是需要實現並提供這些功能給別人使用的角色,而不是享受已經完善的這些功能。 此等尷尬的局面使得 C++ 沒能夠吃下那些屬於 C 語言的領土。

當然我們可以選擇停用或刪除某些 C++ 的功能特性(當然前題是編譯器要能夠支援這麼玩), 以免除前述的一些 C++ 過於肥胖臃腫的問題,而我自己在將 C++ 使用到案子裡的時候往往就是這麼做的。 但是這就很有趣了,這表示 C++ 的問題有時候並不是給的不夠,而是給的太多! 並且更加弔詭的問題是,如果將 C++ 的功能過度現縮之後,使用 C++ 的意義也同樣在喪失! 舉個例子,我看過許多產業介實際的程式碼, 用的是 C++ 編譯器、副檔名是 .cpp,但裡面寫的全是 C 碼, 那麼這還能夠算得上是 C++ 程式嗎?

上層領域對手眾多

前面說的那些都是討論在「C 語言所實際佔領並保有優勢的地盤」下的缺點, 那如果在不是那麼令人膽顫心驚且斤斤計較的應用領域上,是不是 C++ 的豐富功能就能夠大放異彩了呢? 這答案既是,也不是。 確實 C++ 最為活躍擅長並能騰雲駕霧的地方不是和 C 去拼底層, 而是在偏向應用層的領域裡去高效的處理各種複雜的工作。 然而這就要說到本篇所強調的重點:「現代」。 現代各種新興程式語言輩出,如 Java、C#、Python、Swift、Lua 等等等等, 各式新生語言興盛且包圍環伺, 它們比 C++ 更加簡單、方便,甚至在不考慮系統資源負載的情況下還能比 C++ 更加強大。 這樣的局面使得 C++ 比上不足,只能在同時滿足了 功能邏輯複雜或資料龐大、且講究效能、且系統資源不至於過度拮据的應用需求下, 得到一些被需要的生存空間。

綜合平均表現最優異

說了這麼多 C++ 的缺點,那麼 C++ 就真的是一無是處了嗎?當然這也不對! C++ 當然也是有點用處的,不然我自己還用著呢?!

雖然 C++ 的任何一項特點都有比它更加優秀的語言存在, 但是 C++ 其實最特別的優點就是各方特性的平均評分總和最高!

論開發速度與難度,比不上 Python 等新秀,但它們在處理複雜演算法和大量資料時候的性能顯然沒有 C++ 優秀; 論效能比不上 C 語言的高效精減,但 C++ 的開發效率與容易度可贏過太多,並且功能更加豐富強大; 雖然 C++ 對於 C 等經常與底層打交道的語言來說往往過於臃腫肥大而難以勝任最接近機器的工作條件, 但是在現代檯面上各種高大上語言唱主角的情況下, C++ 卻往往身居它們的底層,作為高效苦力支持者的角色存在,竟然成為了它們的基層功能和服務的供應者。 此外前面那些「其它語言」的各種優勢往往是在依賴「讓各語言可以發揮自己的優勢在擅長的地方」之下的結果, 在現實上為了能使之成立,除了需要有一個可以將它們綁定連繫起來的條件之外, 當然也少不了團隊裡面需要有分別精通這些語言的各別專業開發人員。 而如果你只有自己一個人、並且在一段時間內只能夠負擔學習並使用一種程式語言的話, 那麼 C++ 就會是一個最為適合廣泛需求的語言; 換句話說,如果一個產品因故必須只能使用一種程式語言來實現的話, 那麼 C++ 在絕大多數應用場景裡可能就會是一個綜合評效最佳的程式語言! 這也是為什麼當代許多份量大的程式如遊戲引擎等,仍是以 C++ 作為主力開發語言的主要原因之一!

上一篇:「POSIX Tree Container (tsearch) 避坑指南」
下一篇:「把 C++ 程式碼當直譯腳本執行」