舉報

會員
C語言最佳實踐
最新章節(jié):
后記
本書是魏永明近30年來開發(fā)和維護MiniGUI、HVML等開源項目的經驗總結,旨在幫助有一定C程序編寫經驗的軟件工程師在短時間內有效提高設計能力和編碼水平。全書分為?3?篇。基礎篇從可讀性和可維護性出發(fā),闡述了如何提高代碼的可讀性、用好寫好頭文件、正確理解編譯警告并消除潛在問題、定義和使用常量等,介紹了如何有效利用構建系統生成器(CMake)來維護項目;模式篇闡述了常見的C程序接口設計模式,說明了如何在C程序中解耦代碼和數據、利用子驅動程序實現模型、設計可加載模塊等,介紹了狀態(tài)機的概念以及在C程序中如何利用狀態(tài)機實現分詞器、解析器等;質量篇從性能和單元測試出發(fā),闡述了如何在C程序中避免編寫低效代碼、進行單元測試、使用常見的單元測試框架等,介紹了高效調試C程序的若干技巧和工具。本書適合從事系統軟件、嵌入式或物聯網開發(fā)的C程序員、計算機相關專業(yè)高年級本科生和研究生閱讀。
- 后記 更新時間:2025-02-08 17:43:02
- 13.5 日志
- 13.4.3 Valgrind
- 13.4.2 ASAN
- 13.4.1 Efence
- 13.4 內存診斷工具
- 13.3.3 棧使用錯誤
- 13.3.2 堆使用錯誤
- 13.3.1 靜態(tài)數據使用錯誤
- 13.3 內存使用錯誤
- 13.2.2 疑難雜癥
- 13.2.1 編譯、鏈接錯誤
- 13.2 C程序常見錯誤分類
- 13.1 高效調試的基本原則
- 第13章 高效調試
- 12.4.3 使用現有可信賴的工具生成預期結果
- 12.4.2 測試方法
- 12.4.1 測試目標
- 12.4 實例研究:HVML MATH對象的eval方法
- 12.3.3 CTest
- 12.3.2 GoogleTest
- 12.3.1 GLib Testing
- 12.3 單元測試框架
- 12.2.3 單元測試的自動化
- 12.2.2 單元測試方法和測試用例的選擇
- 12.2.1 單元測試可以無處不在
- 12.2 單元測試的基本方法
- 12.1 單元測試的基本概念和重要性
- 第12章 單元測試
- 11.6 實例研究:達夫設備
- 11.5 實例研究:像素混合的并行計算
- 11.4.3 可表示為64位無符號長整型的自然數
- 11.4.2 可表示為無符號短整型的自然數
- 11.4.1 小于16的自然數
- 11.4 實例研究:如何判斷一個自然數是不是素數
- 11.3.3 字符串的原子化
- 11.3.2 利用哈希算法進行優(yōu)化
- 11.3.1 最直接的實現
- 11.3 實例研究:字符串匹配
- 11.2.3 避免濫用內存分配
- 11.2.2 殺雞莫用牛刀
- 11.2.1 不要做無用功
- 11.2 提高性能的3個基本原則
- 11.1 何謂“性能”
- 第11章 為性能編碼
- 第三篇 質量篇
- 10.4.2 復雜示例:HTML解析器中的分詞器
- 10.4.1 簡單示例:判斷C語言立即數的進制
- 10.4 狀態(tài)機在各類解析器中的應用
- 10.3 正確理解狀態(tài)機
- 10.2 定義一個狀態(tài)機
- 10.1 狀態(tài)機的概念
- 第10章 狀態(tài)機
- 9.5.4 裝載模塊定義的默認合成器
- 9.5.3 派生一個自己的合成器
- 9.5.2 合成器相關的應用程序接口
- 9.5.1 合成器操作集
- 9.5 重用已有子驅動程序的實現
- 9.4 使用可加載模塊支持新的圖片格式
- 9.3.3 可加載模塊的實現要點
- 9.3.2 可加載模塊新舊版本的兼容性
- 9.3.1 可加載模塊的底層機制
- 9.3 可加載模塊的實現原理和要點
- 9.2 軟件棧和可加載模塊的設計原則
- 9.1 可加載模塊的好處
- 第9章 動態(tài)加載模塊
- 8.5.4 反思三:還有哪些可以改進的地方
- 8.5.3 反思二:子驅動程序的實現中是否含有不該有的策略
- 8.5.2 反思一:子驅動程序操作集的定義是否足夠完備和靈活
- 8.5.1 最初的設計和實現
- 8.5 子驅動程序實現模型的演進
- 8.4 正確區(qū)分機制和策略
- 8.3.5 進一步思考
- 8.3.4 內存緩沖區(qū)流對象的子驅動程序實現
- 8.3.3 普通文件流對象的子驅動程序實現
- 8.3.2 子驅動程序操作集
- 8.3.1 子驅動程序上下文結構體指針
- 8.3 子驅動程序實現模型的構成
- 8.2 隨處可見的子驅動程序實現模型
- 8.1 抽象的重要性
- 第8章 子驅動程序實現模型
- 7.5.2 使用程序生成代碼
- 7.5.1 使用宏生成代碼
- 7.5 自動生成代碼
- 7.4.3 進一步優(yōu)化
- 7.4.2 改進的版本
- 7.4.1 最初的實現
- 7.4 更復雜的例子
- 7.3 再來一個例子
- 7.2.2 數據和代碼解耦的版本
- 7.2.1 數據和代碼耦合的版本
- 7.2 一個簡單的例子
- 7.1 解耦代碼和數據的重要性
- 第7章 解耦代碼和數據
- 6.12 綜合范例:PurC中的有序數組
- 6.11.5 擴展接口需要考慮的因素
- 6.11.4 方法4:預留擴展能力
- 6.11.3 方法3:強制使用新接口,將舊接口標記為廢棄或移除
- 6.11.2 方法2:舊接口只是新接口的繞轉接口
- 6.11.1 方法1:新舊接口共存
- 6.11 模式8:接口的擴展和兼容性
- 6.10.3 方法3:迭代器
- 6.10.2 方法2:遍歷回調
- 6.10.1 方法1:遍歷宏
- 6.10 模式7:遍歷和迭代
- 6.9.4 避免過度設計
- 6.9.3 范例3:PurC變體接口中的同類聚合
- 6.9.2 范例2:MiniGUI中圖片裝載接口的同類聚合
- 6.9.1 范例1:STDIO接口中的同類聚合
- 6.9 模式6:同類聚合
- 6.8.2 范例2:在用戶結構體中包含通用節(jié)點結構體
- 6.8.1 范例1:在節(jié)點結構體中保留用戶數據成員
- 6.8 模式5:通用數據結構
- 6.7.3 事件處理器的粒度
- 6.7.2 范例2:glib的事件驅動接口
- 6.7.1 范例1:MiniGUI消息驅動接口
- 6.7 模式4:事件驅動
- 6.6.4 范例2:PurC實例
- 6.6.3 范例1:標準C庫的錯誤碼
- 6.6.2 隱式上下文
- 6.6.1 顯式上下文
- 6.6 模式3:上下文
- 6.5.2 范例2:MiniGUI的曲線生成器函數
- 6.5.1 范例1:標準C庫的qsort()函數及其擴展
- 6.5 模式2:抽象算法
- 6.4.3 范例3:描述符或句柄
- 6.4.2 范例2:讀寫流
- 6.4.1 范例1:變體
- 6.4 模式1:抽象數據類型
- 6.3.2 參數及返回值
- 6.3.1 完備性的保證
- 6.3 一般性方法和技巧
- 6.2 兩個接口設計原則
- 6.1 何謂好接口
- 第6章 接口設計模式
- 第二篇 模式篇
- 5.3.5 自定義功能測試
- 5.3.4 查找第三方軟件包
- 5.3.3 檢測系統頭文件、函數或結構體成員
- 5.3.2 多平臺支持
- 5.3.1 整體結構和復制步驟
- 5.3 CMake構建體系模板
- 5.2.3 自動生成代碼
- 5.2.2 處理平臺差異
- 5.2.1 構建類型
- 5.2 CMake影響編碼的選項或功能
- 5.1 常用構建系統和構建系統生成器
- 第5章 充分利用構建系統生成器
- 4.4 字符串的原子化
- 4.3.3 巧用編譯時斷言
- 4.3.2 使用宏生成常量和代碼
- 4.3.1 借助編譯器
- 4.3 優(yōu)雅定義和使用常量
- 4.2.2 字符串常量
- 4.2.1 立即數常量
- 4.2 正確定義和使用常量
- 4.1.2 字符串常量
- 4.1.1 立即數常量
- 4.1 常見的常量使用問題
- 第4章 常量的定義和使用
- 3.4 消除編譯警告只是開始
- 3.3.5 其他函數屬性
- 3.3.4 format屬性
- 3.3.3 warn_unused_result屬性
- 3.3.2 nonnull屬性
- 3.3.1 malloc屬性
- 3.3 編譯警告和函數屬性
- 3.2.8 其他警告
- 3.2.7 詞法警告
- 3.2.6 格式化相關警告
- 3.2.5 邏輯運算相關的警告
- 3.2.4 類型安全警告
- 3.2.3 未初始化警告
- 3.2.2 未使用警告
- 3.2.1 預處理警告
- 3.2 常見的編譯警告及其分類
- 3.1.2 解讀編譯警告
- 3.1.1 潛在問題恐釀成大禍
- 3.1 為什么不能忽視編譯警告
- 第3章 消除編譯警告
- 2.4.3 頭文件的組織
- 2.4.2 頭文件的劃分及典型內容
- 2.4.1 兩大原則
- 2.4 頭文件相關的最佳實踐
- 2.3.5 未妥善處理可能的可移植性問題
- 2.3.4 包含不該出現在頭文件中的內容
- 2.3.3 未處理可能的重復定義
- 2.3.2 未正確處理和C++程序混用的情形
- 2.3.1 不使用或不當定義頭文件保衛(wèi)宏
- 2.3 自定義頭文件中的常見問題
- 2.2 濫用系統頭文件的負面影響
- 2.1.3 頭文件機制的復雜性
- 2.1.2 頭文件的分類
- 2.1.1 頭文件的作用
- 2.1 重新認識頭文件
- 第2章 用好寫好頭文件
- 1.7.2 經典的list_head結構體及其接口
- 1.7.1 PurC函數庫頭文件
- 1.7 實例分析
- 1.6 命名的藝術
- 1.5.3 參數的合法性檢查
- 1.5.2 錯誤處理及集中返回
- 1.5.1 下畫線前綴的使用
- 1.5 其他有關編碼風格的最佳實踐
- 1.4.7 優(yōu)雅編寫條件編譯代碼
- 1.4.6 正確書寫注釋
- 1.4.5 命名規(guī)則保持一致
- 1.4.4 善用類型定義
- 1.4.3 指針聲明和定義中的星號位置
- 1.4.2 空格、大括號位置及縮進
- 1.4.1 守好“80列”這條紅線
- 1.4 提高代碼可讀性的最佳實踐
- 1.3.2 其他常見的編碼風格
- 1.3.1 Linux內核編碼風格的一些規(guī)定
- 1.3 編碼風格的內容
- 1.2.2 妙手理碼
- 1.2.1 壞代碼實例
- 1.2 壞代碼的特點
- 1.1 代碼可讀性的級別
- 第1章 提高代碼可讀性
- 第一篇 基礎篇
- 關于異步社區(qū)和異步圖書
- 與我們聯系
- 提交勘誤
- 資源獲取
- 資源與支持
- 前言
- 推薦語
- 內容提要
- 版權
- 版權信息
- 封面
- 封面
- 版權信息
- 版權
- 內容提要
- 推薦語
- 前言
- 資源與支持
- 資源獲取
- 提交勘誤
- 與我們聯系
- 關于異步社區(qū)和異步圖書
- 第一篇 基礎篇
- 第1章 提高代碼可讀性
- 1.1 代碼可讀性的級別
- 1.2 壞代碼的特點
- 1.2.1 壞代碼實例
- 1.2.2 妙手理碼
- 1.3 編碼風格的內容
- 1.3.1 Linux內核編碼風格的一些規(guī)定
- 1.3.2 其他常見的編碼風格
- 1.4 提高代碼可讀性的最佳實踐
- 1.4.1 守好“80列”這條紅線
- 1.4.2 空格、大括號位置及縮進
- 1.4.3 指針聲明和定義中的星號位置
- 1.4.4 善用類型定義
- 1.4.5 命名規(guī)則保持一致
- 1.4.6 正確書寫注釋
- 1.4.7 優(yōu)雅編寫條件編譯代碼
- 1.5 其他有關編碼風格的最佳實踐
- 1.5.1 下畫線前綴的使用
- 1.5.2 錯誤處理及集中返回
- 1.5.3 參數的合法性檢查
- 1.6 命名的藝術
- 1.7 實例分析
- 1.7.1 PurC函數庫頭文件
- 1.7.2 經典的list_head結構體及其接口
- 第2章 用好寫好頭文件
- 2.1 重新認識頭文件
- 2.1.1 頭文件的作用
- 2.1.2 頭文件的分類
- 2.1.3 頭文件機制的復雜性
- 2.2 濫用系統頭文件的負面影響
- 2.3 自定義頭文件中的常見問題
- 2.3.1 不使用或不當定義頭文件保衛(wèi)宏
- 2.3.2 未正確處理和C++程序混用的情形
- 2.3.3 未處理可能的重復定義
- 2.3.4 包含不該出現在頭文件中的內容
- 2.3.5 未妥善處理可能的可移植性問題
- 2.4 頭文件相關的最佳實踐
- 2.4.1 兩大原則
- 2.4.2 頭文件的劃分及典型內容
- 2.4.3 頭文件的組織
- 第3章 消除編譯警告
- 3.1 為什么不能忽視編譯警告
- 3.1.1 潛在問題恐釀成大禍
- 3.1.2 解讀編譯警告
- 3.2 常見的編譯警告及其分類
- 3.2.1 預處理警告
- 3.2.2 未使用警告
- 3.2.3 未初始化警告
- 3.2.4 類型安全警告
- 3.2.5 邏輯運算相關的警告
- 3.2.6 格式化相關警告
- 3.2.7 詞法警告
- 3.2.8 其他警告
- 3.3 編譯警告和函數屬性
- 3.3.1 malloc屬性
- 3.3.2 nonnull屬性
- 3.3.3 warn_unused_result屬性
- 3.3.4 format屬性
- 3.3.5 其他函數屬性
- 3.4 消除編譯警告只是開始
- 第4章 常量的定義和使用
- 4.1 常見的常量使用問題
- 4.1.1 立即數常量
- 4.1.2 字符串常量
- 4.2 正確定義和使用常量
- 4.2.1 立即數常量
- 4.2.2 字符串常量
- 4.3 優(yōu)雅定義和使用常量
- 4.3.1 借助編譯器
- 4.3.2 使用宏生成常量和代碼
- 4.3.3 巧用編譯時斷言
- 4.4 字符串的原子化
- 第5章 充分利用構建系統生成器
- 5.1 常用構建系統和構建系統生成器
- 5.2 CMake影響編碼的選項或功能
- 5.2.1 構建類型
- 5.2.2 處理平臺差異
- 5.2.3 自動生成代碼
- 5.3 CMake構建體系模板
- 5.3.1 整體結構和復制步驟
- 5.3.2 多平臺支持
- 5.3.3 檢測系統頭文件、函數或結構體成員
- 5.3.4 查找第三方軟件包
- 5.3.5 自定義功能測試
- 第二篇 模式篇
- 第6章 接口設計模式
- 6.1 何謂好接口
- 6.2 兩個接口設計原則
- 6.3 一般性方法和技巧
- 6.3.1 完備性的保證
- 6.3.2 參數及返回值
- 6.4 模式1:抽象數據類型
- 6.4.1 范例1:變體
- 6.4.2 范例2:讀寫流
- 6.4.3 范例3:描述符或句柄
- 6.5 模式2:抽象算法
- 6.5.1 范例1:標準C庫的qsort()函數及其擴展
- 6.5.2 范例2:MiniGUI的曲線生成器函數
- 6.6 模式3:上下文
- 6.6.1 顯式上下文
- 6.6.2 隱式上下文
- 6.6.3 范例1:標準C庫的錯誤碼
- 6.6.4 范例2:PurC實例
- 6.7 模式4:事件驅動
- 6.7.1 范例1:MiniGUI消息驅動接口
- 6.7.2 范例2:glib的事件驅動接口
- 6.7.3 事件處理器的粒度
- 6.8 模式5:通用數據結構
- 6.8.1 范例1:在節(jié)點結構體中保留用戶數據成員
- 6.8.2 范例2:在用戶結構體中包含通用節(jié)點結構體
- 6.9 模式6:同類聚合
- 6.9.1 范例1:STDIO接口中的同類聚合
- 6.9.2 范例2:MiniGUI中圖片裝載接口的同類聚合
- 6.9.3 范例3:PurC變體接口中的同類聚合
- 6.9.4 避免過度設計
- 6.10 模式7:遍歷和迭代
- 6.10.1 方法1:遍歷宏
- 6.10.2 方法2:遍歷回調
- 6.10.3 方法3:迭代器
- 6.11 模式8:接口的擴展和兼容性
- 6.11.1 方法1:新舊接口共存
- 6.11.2 方法2:舊接口只是新接口的繞轉接口
- 6.11.3 方法3:強制使用新接口,將舊接口標記為廢棄或移除
- 6.11.4 方法4:預留擴展能力
- 6.11.5 擴展接口需要考慮的因素
- 6.12 綜合范例:PurC中的有序數組
- 第7章 解耦代碼和數據
- 7.1 解耦代碼和數據的重要性
- 7.2 一個簡單的例子
- 7.2.1 數據和代碼耦合的版本
- 7.2.2 數據和代碼解耦的版本
- 7.3 再來一個例子
- 7.4 更復雜的例子
- 7.4.1 最初的實現
- 7.4.2 改進的版本
- 7.4.3 進一步優(yōu)化
- 7.5 自動生成代碼
- 7.5.1 使用宏生成代碼
- 7.5.2 使用程序生成代碼
- 第8章 子驅動程序實現模型
- 8.1 抽象的重要性
- 8.2 隨處可見的子驅動程序實現模型
- 8.3 子驅動程序實現模型的構成
- 8.3.1 子驅動程序上下文結構體指針
- 8.3.2 子驅動程序操作集
- 8.3.3 普通文件流對象的子驅動程序實現
- 8.3.4 內存緩沖區(qū)流對象的子驅動程序實現
- 8.3.5 進一步思考
- 8.4 正確區(qū)分機制和策略
- 8.5 子驅動程序實現模型的演進
- 8.5.1 最初的設計和實現
- 8.5.2 反思一:子驅動程序操作集的定義是否足夠完備和靈活
- 8.5.3 反思二:子驅動程序的實現中是否含有不該有的策略
- 8.5.4 反思三:還有哪些可以改進的地方
- 第9章 動態(tài)加載模塊
- 9.1 可加載模塊的好處
- 9.2 軟件棧和可加載模塊的設計原則
- 9.3 可加載模塊的實現原理和要點
- 9.3.1 可加載模塊的底層機制
- 9.3.2 可加載模塊新舊版本的兼容性
- 9.3.3 可加載模塊的實現要點
- 9.4 使用可加載模塊支持新的圖片格式
- 9.5 重用已有子驅動程序的實現
- 9.5.1 合成器操作集
- 9.5.2 合成器相關的應用程序接口
- 9.5.3 派生一個自己的合成器
- 9.5.4 裝載模塊定義的默認合成器
- 第10章 狀態(tài)機
- 10.1 狀態(tài)機的概念
- 10.2 定義一個狀態(tài)機
- 10.3 正確理解狀態(tài)機
- 10.4 狀態(tài)機在各類解析器中的應用
- 10.4.1 簡單示例:判斷C語言立即數的進制
- 10.4.2 復雜示例:HTML解析器中的分詞器
- 第三篇 質量篇
- 第11章 為性能編碼
- 11.1 何謂“性能”
- 11.2 提高性能的3個基本原則
- 11.2.1 不要做無用功
- 11.2.2 殺雞莫用牛刀
- 11.2.3 避免濫用內存分配
- 11.3 實例研究:字符串匹配
- 11.3.1 最直接的實現
- 11.3.2 利用哈希算法進行優(yōu)化
- 11.3.3 字符串的原子化
- 11.4 實例研究:如何判斷一個自然數是不是素數
- 11.4.1 小于16的自然數
- 11.4.2 可表示為無符號短整型的自然數
- 11.4.3 可表示為64位無符號長整型的自然數
- 11.5 實例研究:像素混合的并行計算
- 11.6 實例研究:達夫設備
- 第12章 單元測試
- 12.1 單元測試的基本概念和重要性
- 12.2 單元測試的基本方法
- 12.2.1 單元測試可以無處不在
- 12.2.2 單元測試方法和測試用例的選擇
- 12.2.3 單元測試的自動化
- 12.3 單元測試框架
- 12.3.1 GLib Testing
- 12.3.2 GoogleTest
- 12.3.3 CTest
- 12.4 實例研究:HVML MATH對象的eval方法
- 12.4.1 測試目標
- 12.4.2 測試方法
- 12.4.3 使用現有可信賴的工具生成預期結果
- 第13章 高效調試
- 13.1 高效調試的基本原則
- 13.2 C程序常見錯誤分類
- 13.2.1 編譯、鏈接錯誤
- 13.2.2 疑難雜癥
- 13.3 內存使用錯誤
- 13.3.1 靜態(tài)數據使用錯誤
- 13.3.2 堆使用錯誤
- 13.3.3 棧使用錯誤
- 13.4 內存診斷工具
- 13.4.1 Efence
- 13.4.2 ASAN
- 13.4.3 Valgrind
- 13.5 日志
- 后記 更新時間:2025-02-08 17:43:02