- C語言最佳實踐
- 魏永明
- 2488字
- 2025-02-08 17:41:55
前言
C語言誕生于貝爾實驗室。1972年,Dennis Ritchie在Kenneth Lane Thompson設計的B語言基礎上發展出了C語言。在C語言的主體設計完成后,Thompson和Ritchie重寫了UNIX操作系統。隨著UNIX操作系統的發展,C語言也得到了進一步的完善,并在1989年誕生了第一個完備的C語言標準——C89,也就是廣為人知的ANSI C。盡管C語言的誕生和UNIX操作系統密不可分,但 C 語言已經成為幾乎所有操作系統支持的編程語言,廣泛應用于操作系統內核、基礎函數庫、數據庫、圖形系統、密碼系統、多媒體編解碼器等的開發中。因此,在各類編程語言排行榜上,C語言始終名列前茅。
C語言廣泛應用于系統底層的開發當中,這是因為C語言是最接近計算機處理器的編程語言。C語言可產生接近匯編語言執行效率的機器指令,同時保持非常好的跨平臺特性。由于操作系統內核、基礎函數庫、數據庫等大量的基礎軟件使用C語言開發,甚至許多腳本編程語言(如Python)的解釋器也使用C語言開發,因此將C語言稱作人類迄今為止創建的整個軟件生態的底座,相信沒有人會提出異議。
在筆者看來,C語言最大的優點在于其設計上的完備性和簡潔性。完備性在于開發者可以使用C語言實現任何想得到的功能,而簡潔性確保了C語言特性的穩定。相比其他編程語言,比如C++,C語言的關鍵詞(又稱關鍵字或保留字)、數據類型和語法等特性非常穩定。自從C89一字不落地被國際標準化組織吸納成為ISO/IEC 9899標準之后,國際標準化組織和國際電工委員會僅在1999年、2011年和2018年對C語言標準做了一些修正和完善,分別發布了C99、C11和C18標準(現階段被廣泛接受和使用的C語言標準仍然是C99)。這些標準之間的差異很小,且向后兼容。但假如一名20年前的C++程序員穿越到現在閱讀最新的C++程序代碼,一定會驚呼“宛如天書”!
在半個多世紀的計算機軟件發展史上,出現了眾多的編程語言,大量的編程語言曇花一現,還沒流行就消失在歷史的長河中,還有一些編程語言曾經盛極一時,但隨后默默無聞。由于 C 語言的特殊地位,我們有理由相信它將會長盛不衰。
近幾年,國內開始重視操作系統、數據庫、開發工具甚至編程語言等基礎軟件的國產化,這些基礎軟件哪一個離得開C語言呢?然而,我國有大量程序員任職于互聯網公司,日常使用的是JavaScript、PHP、Java、Python等編程語言,C程序員則主要活躍于嵌入式和物聯網領域,人數相對較少。
除了人員數量少,算得上“八級工”水平的C程序員更是鳳毛麟角。筆者在近30年的軟件開發生涯中,看到過很多C程序員,即便是有多年從業經驗的程序員,也不能有效使用C語言編寫程序。盡管很多C程序在語法上沒有什么問題——畢竟可以運行的程序起碼要通過編譯器的編譯——但在很多方面存在或多或少的問題,具體如下。
● 不注重代碼的可讀性,寫出來的代碼沒有美感和章法。
● 不會給函數、變量、結構成員等取名,甚至使用拼音。
● 不注重細節,比如定義一個字符數組作為緩沖區,隨意填寫其大小。
● 不嚴謹,對編譯時出現的大量警告視而不見。
以上這些其實都是一些基礎性的問題,屬于代碼可讀性和可維護性的范疇,作為一名合格的C程序員,必須給予充分重視并糾正。相比起來,這些問題還算好解決。但如果進一步談到C程序的常見設計和實現模式,比如設計接口、解耦代碼和數據、利用子驅動程序實現模型、設計狀態機等,則絕大多數C程序員會感到難以理解和駕馭。
筆者在1993年接觸C語言,起初在DOS下開發C程序,1998年年底為嵌入式Linux開發窗口系統MiniGUI,并領導團隊持續開發和維護MiniGUI開源項目。20多年來,MiniGUI一直廣泛應用于各類嵌入式設備當中。2020年,筆者提出了HVML編程語言,并領導團隊使用C/C++開發HVML編程語言的開源解釋器(PurC)和渲染器(xGUI Pro)。在開發PurC的過程中,筆者觀察到團隊成員在使用C語言方面的諸多問題,且發現這些問題具有普遍性,于是在2021年下半年利用視頻號平臺發起了一項公益性直播課程“C語言最佳實踐”。此課程的回放隨后在Bilibili平臺上發布,并獲得大量好評。2022 年年初,人民郵電出版社邀請筆者將直播課程整理成書,于是便有了本書。
可以說,本書是筆者近30年編碼經驗的總結。全書分3篇:基礎篇、模式篇和質量篇。
基礎篇(第1章~第5章)從可讀性和可維護性出發,闡述了如何提高代碼的可讀性、用好寫好頭文件、正確理解編譯警告并消除潛在問題、定義和使用常量等,介紹了如何有效利用構建系統生成器(CMake)來維護項目,比如提高代碼的可移植性、處理可選的功能模塊,以及自動生成某些源代碼等。C語言最為接近計算機處理器,因而可以取得最佳的性能表現,但硬幣的另一面則是容易寫出一些存在缺陷和安全漏洞的代碼。而這些缺陷或安全漏洞往往和程序員編碼時不嚴謹有關。本篇的內容旨在幫助C程序員理解不嚴謹的編碼風格和漠視編譯警告所帶來的風險,從而為寫出高質量的C代碼打下基礎。
模式篇(第6章~第10章)是本書的核心內容,闡述了常見的C程序接口設計模式,說明了如何在C程序中解耦代碼和數據、利用子驅動程序實現模型、設計可加載模塊等,介紹了狀態機的概念以及在C程序中如何利用狀態機實現分詞器、解析器等。第6章介紹的8種C程序接口設計模式是本書的重點,在其他C語言圖書中鮮有介紹。本篇的內容旨在幫助C程序員開發出具有良好的接口設計且兼顧可維護性和可擴展性的C程序。
質量篇(第11章~第13章)從性能和單元測試出發,闡述了如何避免編寫低效代碼、進行單元測試、使用常見的單元測試框架等,介紹了高效調試C程序的若干技巧和工具。本篇的內容旨在幫助C程序員編寫兼顧性能的高質量C代碼。
本書的很多示例代碼來自筆者主導的如下兩個開源項目。
● MiniGUI。MiniGUI是一個開源的跨平臺窗口系統,支持10多種操作系統,并提供豐富的小部件/控件和開源應用程序及工具。參見GitHub上的VincentWei/MiniGUI庫。
● PurC。PurC是HVML的解釋器,HVML是由筆者提出的一種描述式編程語言。參見GitHub上的HVML/PurC庫。
本書帶有配套示例程序,供讀者閱讀時同步參考,參見“資源與支持”頁。完整的示例程序整理在GitHub上的VincentWei/bpcp庫中。
讀者亦可掃描書中所附二維碼在線查看更多參考資料。
本書使用了如下術語。
● 結構體(structure):用于指代C程序中使用struct關鍵詞定義的數據結構。
● 成員(member):結構體中的成員;為防止混淆,本書不使用字段(field)這一術語。
● 頭文件(header file):特指.h文件。
● 源文件(source file):特指.c文件。
魏永明
2024年8月