C++代碼風格指南
代碼風格的重要性
今天我收到thougthwork筆試沒過的消息, 內心確實很難受, 而後師兄說我代碼寫得很糟糕
細想一下, 我寫代碼確實是爲所欲爲, 並無遵循什麼規範; 因此如今下定決心痛改前非;c++
- 首先第一步是代碼都本身一個字一個字的敲, 儘可能減小
Ctrl+C
和Ctrl+V
操做
- 之後禁止使用
tab
鍵進行縮進,難道手敲四個空格會死麼?
- 避免代碼冗長
- Google開源項目C++代碼風格指南
頭文件
- 頭文件包含順序
- 優先位置的包含文件
- C系統文件
- C++系統文件
- 其餘庫的.h文件
- 本庫的.h文件
做用域
- 禁止使用 using 指示(using-directive)
- 禁止使用內聯命名空間(inline namespace)
- 由於內聯的命名空間會內部的標識符放到外層做用域
- 內聯命名空間主要用來保持跨版本的 ABI 兼容性
- 在頭文件中使用匿名空間致使違背 C++ 的惟必定義原則 (One Definition Rule (ODR)).
- 不該該使用 using 指示引入整個命名空間的標識符號 ---- 會污染命名空間
- 不要在命名空間 std 內聲明任何東西, 包括標準庫的類前置聲明. 在 std 命名空間聲明實體是未定義的行爲, 會致使如不可移植. 聲明標準庫下的實體, 須要包含對應的頭文件.
- 匿名命名空間和靜態空間(內部連接屬性)
- 在 .cc 文件中定義一個不須要被外部引用的變量時,能夠將它們放在匿名命名空間或聲明爲
static
; 可是不要在 .h
文件中這麼作
- 全部置於匿名命名空間的聲明都具備內部連接性,函數和變量能夠經由聲明爲
static
擁有內部連接性,這意味着你在這個文件中聲明的這些標識符都不能在另外一個文件中被訪問。即便兩個文件聲明瞭徹底同樣名字的標識符,它們所指向的實體其實是徹底不一樣的。
- 靜態成員函數, 全局函數, 和非成員函數
- 將一系列函數直接置於命名空間中,不要用類的靜態方法模擬出命名空間的效果,類的靜態方法應當和類的實例或靜態數據緊密相關.
- 局部變量
- 將函數變量儘量置於最小做用域內, 並在變量聲明時進行初始化.
- 提倡在儘量小的做用域中聲明變量, 離第一次使用越近越好.
- 這樣作的好處是閱讀代碼能夠更容易定位變量的聲明位置, 瞭解變量的初始值和類型,特別是利用初始化的方式代替聲明再賦值的方式.
- 警告: 若是變量是一個對象, 每次進入做用域都要調用其構造函數, 每次退出做用域都要調用其析構函數. 這會致使效率下降.
- 靜態和全局變量
- 禁止定義靜態儲存週期非POD變量(原生數據類型 (POD : Plain Old Data)),禁止使用含有反作用的函數初始化POD全局變量,由於多編譯單元中的靜態變量執行時的構造和析構順序是未明確的,這將致使代碼的不可移植.
- 靜態變量的構造函數和析構函數在C++中只有部分明確肯定, 甚至隨着構建變化而變化, 致使難以發現的bug.
- 儘可能不要使用函數的返回值來初始化一個變量
- 同一個編譯單元內是明確的,靜態初始化優先於動態初始化,初始化順序按照聲明順序進行,銷燬則逆序。
- 不一樣的編譯單元之間初始化和銷燬順序屬於未明確行爲 (unspecified behaviour)。
- 全局和靜態變量在程序中斷時會被析構, --- 析構順序和構造函數的調用順序相反。
- quick_exit() 來代替 exit() 並中斷程序。quick_exit 不會執行任何析構,也不會執行 atexit() 所綁定的任何 handlers.
- 只容許 POD(原生數據類型) 類型的靜態變量
- static 對象, 能夠考慮在 main() 函數或 pthread_once() 內初始化一個指針且永不回收, 只能使用raw指針.
- 別用智能指針,畢竟後者的析構函數涉及不定順序問題
- 匿名命名空間說白了就是文件做用域,就像 C static 聲明的做用域同樣,後者已經被 C++ 標準提倡棄用
- 局部變量在聲明的同時進行顯式值初始化,比起隱式初始化再賦值的兩步過程要高效,同時也貫徹了計算機體系結構重要的概念「局部性(locality)」
類
- 不要在構造函數中調用虛函數, 也不要在沒法報出錯誤時進行可能失敗的初始化.
- 構造函數的地址是沒法被取得的, 所以, 舉例來講, 由構造函數完成的工做是沒法以簡單的方式交給其餘線程的.
- 不要定義隱式類型轉換. 對於轉換運算符和單參數構造函數, 請使用 explicit 關鍵字.
- 在類型定義中, 類型轉換運算符和單參數構造函數都應當用 explicit 進行標記. 一個例外是, 拷貝和移動構造函數不該當被標記爲 explicit, 由於它們並不執行類型轉換. 對於設計目的就是用於對其餘類型進行透明包裝的類來講, 隱式類型轉換有時是必要且合適的. 這時應當聯繫項目組長並說明特殊狀況.
- 僅當只有數據成員時使用 struct, 其它一律使用 class.
- 爲了和 STL 保持一致, 對於仿函數等特性能夠不用 class 而是使用 struct.
- 不在構造函數中作太多邏輯相關的初始化;
- 編譯器提供的默認構造函數不會對變量進行初始化, 若是定義了其餘構造函數, 編譯器再也不提供, 須要編碼者自行提供默認構造函數;
- 爲避免隱式轉換, 需將單參數構造函數聲明爲 explicit;
- 爲避免拷貝構造函數, 賦值操做的濫用和編譯器自動生成, 可將其聲明爲 private 且無需實現;
- 僅在做爲數據集合時使用 struct;
- 組合 > 實現繼承 > 接口繼承 > 私有繼承, 子類重載的虛函數也要聲明 virtual 關鍵字, 雖然編譯器容許不這樣作;
- 避免使用多重繼承, 使用時, 除一個基類含有實現外, 其餘基類均爲純接口;
- 接口類類名以 Interface 爲後綴, 除提供帶實現的虛析構函數, 靜態成員函數外, 其餘均爲純虛函數, 不定義非靜態數據成員, 不提供構造函數, 提供的話, 聲明爲 protected;
- 爲下降複雜性, 儘可能不重載操做符, 模板, 標準類中使用時提供文檔說明;
- 存取函數通常內聯在頭文件中;
- 聲明次序: public -> protected -> private;
- 函數體儘可能短小, 緊湊, 功能單一;
函數
- 在排列參數順序時, 將全部的輸入參數置於輸出參數以前. 特別要注意, 在加入新參數時不要由於它們是新參數就置於參數列表最後, 而是仍然要按照前述的規則, 即將新的輸入參數也置於輸出參數以前.
- 傾向於編寫簡短, 凝練的函數.
- 能夠思索一下能不能在不影響程序結構的前提下對其進行分割.
- 全部按引用傳遞的參數必須加上 const.
- 定義引用參數能夠防止出現 (*pval)++ 這樣醜陋的代碼. 引用參數對於拷貝構造函數這樣的應用也是必需的. 同時也更明確地不接受空指針.
- 引用在語法上是值變量卻擁有指針的語義.
- 輸入參數是值參或 const 引用, 輸出參數爲指針. 輸入參數能夠是 const 指針, 但決不能是非 const 的引用參數, 除非特殊要求, 好比 swap().
- 只容許在非虛函數中使用缺省參數, 且必須保證缺省參數的值始終一致.
- 對於虛函數, 不容許使用缺省參數, 由於在虛函數中缺省參數不必定能正常工做.
- 只有在常規寫法 (返回類型前置) 不便於書寫或不便於閱讀時使用返回類型後置語法. --- 後置返回類型是顯式地指定 Lambda 表達式 的返回值的惟一方式.
來自Google的奇技
- Google用了不少本身實現的技巧/工具C++代碼更加健壯
- 全部權與智能指針: 動態分配出的對象最好有單一且固定的全部主, 並經過智能指針傳遞全部權.
- 智能指針是重載了
*
和->
運算符以表現得像指針同樣的類
unique_ptr
將全部權移動給新全部主
shared_ptr
表示動態分配對象的全部權, 但能夠被共享, 也能夠被複制
- 若是沒有很好的理由就不要使用共享版全部權, 是爲了不開銷昂貴的拷貝操做.
- 不要使用
auto_ptr
, 使用shared_ptr
代替它.
- 使用cpplint.py檢查代碼風格, cpplint.py是一個用來分析源文件, 能檢查出多種風格錯誤的工具.
- scoped_ptr 和 auto_ptr 已過期. 如今是 shared_ptr 和 uniqued_ptr 的天下了.
- AUR有對cpplint打包.
其餘C++特性
- 引用參數: 全部按引用傳遞的參數必須加上
const
- 引用在語法上是值變量卻擁有指針的語義.
- 輸入參數是值參或 const 引用, 輸出參數爲指針. 輸入參數能夠是 const 指針, 但決不能是非 const 的引用參數,除非用於交換.
- 有時候,在輸入形參中用 const T* 指針比 const T& 更明智.
- 右值的引用: 只在定義移動構造函數與移動賦值操做時使用右值引用. 不要使用 std::forward.
- 右值引用是一種只能綁定到臨時對象的引用的一種, 其語法與傳統的引用語法類似.
- 用於定義移動構造函數 (使用類的右值引用進行構造的函數) 使得移動一個值而非拷貝之成爲可能.
- 要高效率地使用某些標準庫類型, 例如 std::unique_ptr, std::move 是必需的.
- 函數重載: 若要用好函數重載,最好能讓讀者一看調用點(call site)就成竹在胸,不用花心思猜想調用的重載函數究竟是哪種。該規則適用於構造函數.
- 缺省參數: 咱們不容許使用缺省函數參數,少數極端狀況除外。儘量改用函數重載.
- 缺省參數會干擾函數簽名(function signature), 每每對不上所實際要調用的函數簽名
- 其一,位於 .cc 文件裏的靜態函數或匿名空間函數,畢竟都只能在局部文件裏調用該函數了。
- 其二,能夠在構造函數裏用缺省參數,畢竟不可能取得它們的地址。
- 其三,能夠用來模擬變長數組。
- 變長數組和alloca()
- 咱們不容許使用變長數組和 alloca().
- 變長數組具備渾然天成的語法. 變長數組和 alloca() 也都很高效; 可是不是標準C++語法的一部分.
- 改用更安全的分配器(allocator),就像 std::vector 或 std::unique_ptr<T[]>
- 友元(friend)
- 咱們容許合理的使用友元類及友元函數.
- 一般友元應該定義在同一文件內, 避免代碼讀者跑到其它文件查找使用該私有成員的類.
- 將一個單元測試類聲明成待測類的友元會很方便.
- 友元擴大了 (但沒有打破) 類的封裝邊界. 某些狀況下, 相對於將類成員聲明爲 public, 使用友元是更好的選擇, 尤爲是若是你只容許另外一個類訪問該類的私有成員時. 固然, 大多數類都只應該經過其提供的公有成員進行互操做.
- 異常
- 咱們不使用 C++ 異常.
- 異常容許應用高層決定如何處理在底層嵌套函數中「不可能發生」的失敗(failures),不用管那些含糊且容易出錯的錯誤代碼.
- 異常是處理構造函數失敗的惟一途徑.
- 異常會完全擾亂程序的執行流程並難以判斷,函數也許會在您意料不到的地方返回.
- 對於異常處理, 顯然不是短短几句話可以說清楚的, 以構造函數爲例, 不少 C++ 書籍上都提到當構造失敗時只有異常能夠處理, Google 禁止使用異常這一點, 僅僅是爲了自身的方便, 說大了, 無非是基於軟件管理成本上, 實際使用中仍是本身決定
- 運行時類型識別(run time type information RTTI)
- RTTI 容許程序員在運行時識別 C++ 類對象的類型. 它經過使用 typeid 或者 dynamic_cast 完成.
- 在單元測試中可使用 RTTI, 可是在其餘代碼中請儘可能避免. 尤爲是在新代碼中, 使用 RTTI 前務必三思. 若是你的代碼須要根據不一樣的對象類型執行不一樣的行爲的話, 請考慮用如下的兩種替代方案之一查詢類型.
- 虛函數能夠根據子類類型的不一樣而執行不一樣代碼.
- 類型轉型
- 使用 C++ 的類型轉換, 如 static_cast<>(). 不要使用 int y = (int)x 或 int y = int(x) 等轉換方式
- C++ 採用了有別於 C 的類型轉換機制, 對轉換操做進行歸類.
- 用 static_cast 替代 C 風格的值轉換, 或某個類指針須要明確的向上轉換爲父類指針時.
- 用 const_cast 去掉 const 限定符.
- 用 reinterpret_cast 指針類型和整型或其它指針之間進行不安全的相互轉換. 僅在你對所作一切瞭然於心時使用.
- 用 dynatic_cast 將派生類指針轉換爲基類類型, 或將基類指針轉換爲派生類指針.
- 流
- 只在記錄日誌時使用流.
- 流用來替代 printf() 和 scanf().
- 有了流, 在打印時不須要關心對象的類型.
- 流的構造和析構函數會自動打開和關閉對應的文件.
- 使用流還有不少利弊, 但代碼一致性賽過一切. 不要在代碼中使用流.
- 回想一下惟一性原則 (Only One Way): 咱們但願在任什麼時候候都只使用一種肯定的 I/O 類型, 使代碼在全部 I/O 處都保持一致.
- 簡單性原則告誡咱們必須從中選擇其一, 最後大多數決定採用 printf + read/write.
- 前置自增或自減
- 對於迭代器和其餘模板對象使用前綴形式 (++i) 的自增, 自減運算符.
- 不考慮返回值的話, 前置自增 (++i) 一般要比後置自增 (i++) 效率更高. 由於後置自增 (或自減) 須要對錶達式的值 i 進行一次拷貝.
- 對簡單數值 (非對象), 兩種都無所謂. 對迭代器和模板類型, 使用前置自增 (自減).
- const 用法
- 咱們強烈建議你在任何可能的狀況下都要使用 const. 此外有時改用 C++11 推出的 constexpr 更好.
- 在聲明的變量或參數前加上關鍵字 const 用於指明變量值不可被篡改 (如 const int foo ). 爲類中的函數加上 const 限定符代表該函數不會修改類成員變量的狀態
- 你們更容易理解如何使用變量. 編譯器能夠更好地進行類型檢測, 相應地, 也能生成更好的代碼.
- 若是函數不會修改傳你入的引用或指針類型參數, 該參數應聲明爲 const.
- 儘量將函數聲明爲 const. 訪問函數應該老是 const. 其餘不會修改任何數據成員, 未調用非 const 函數, 不會返回數據成員非 const 指針或引用的函數也應該聲明成 const.
- 若是數據成員在對象構造以後再也不發生變化, 可將其定義爲 const.
- 關鍵字 mutable 可使用, 可是在多線程中是不安全的, 使用時首先要考慮線程安全.
- 保持代碼的一致性: 也就是不要在一些地方把 const 寫在類型前面, 在其餘地方又寫在後面, 肯定一種寫法, 而後保持一致.
- constexpr 用法
- 在 C++11 裏,用 constexpr 來定義真正的常量,或實現常量初始化
- 變量能夠被聲明成 constexpr 以表示它是真正意義上的常量,即在編譯時和運行時都不變。函數或構造函數也能夠被聲明成 constexpr, 以用來定義 constexpr 變量
- 靠 constexpr 特性,方纔實現了 C++ 在接口上打造真正常量機制的可能。好好用 constexpr 來定義真・常量以及支持常量的函數。避免複雜的函數定義,以使其可以與constexpr一塊兒使用。 千萬別癡心妄想地想靠 constexpr 來強制代碼「內聯
- constexpr關鍵字詳解
- constexpr編譯時常量
- 整數
- C++ 內建整型中, 僅使用 int. 若是程序中須要不一樣大小的變量, 可使用 <stdint.h> 中長度精確的整型, 如 int16_t.若是您的變量可能不小於 2^31 (2GiB), 就用 64 位變量好比 int64_t. 此外要留意,哪怕您的值並不會超出 int 所可以表示的範圍,在計算過程當中也可能會溢出。因此拿不許時,乾脆用更大的類型
- C++ 沒有指定整型的大小. 一般人們假定 short 是 16 位, int 是 32 位, long 是 32 位, long long 是 64 位.
- C++ 中整型大小因編譯器和體系結構的不一樣而不一樣.
- 應該使用斷言來保護數據.
- 使用斷言來指出變量爲非負數, 而不是使用無符號型
- 64位下的可移植性
- 代碼應該對 64 位和 32 位系統友好. 處理打印, 比較, 結構體對齊時應切記
- 持久化 - 將數據按字節流順序保存在磁盤文件或數據庫中.
- gcc 中可以使用
__attribute__((packed))
使結構體對齊
- 預處理宏
- 使用宏時要很是謹慎, 儘可能之內聯函數, 枚舉和常量代替之.
- 宏意味着你和編譯器看到的代碼是不一樣的. 這可能會致使異常行爲, 尤爲由於宏具備全局做用域.
- 下面給出的用法模式能夠避免使用宏帶來的問題; 若是你要宏, 儘量遵照:
- 不要在 .h 文件中定義宏.
- 在立刻要使用時才進行 #define, 使用後要當即 #undef.
- 不要只是對已經存在的宏使用#undef,選擇一個不會衝突的名稱;
- 不要試圖使用展開後會致使 C++ 構造不穩定的宏, 否則也至少要附上文檔說明其行爲.
- 不要用 ## 處理函數,類和變量的名字
- 0 , NULL 和 nullptr
- 整數用 0, 實數用 0.0, 指針用 nullptr 或 NULL, 字符 (串) 用 '\0'.
- 對於指針 (地址值), 究竟是用 0, NULL 仍是 nullptr. C++11 項目用 nullptr; C++03 項目則用 NULL, 畢竟它看起來像指針。實際上,一些 C++ 編譯器對 NULL 的定義比較特殊,能夠輸出有用的警告,特別是 sizeof(NULL) 就和 sizeof(0) 不同。
- 字符 (串) 用 '\0', 不只類型正確並且可讀性好.
- sizeof
- 儘量用 sizeof(varname) 代替 sizeof(type).
- auto
- 用 auto 繞過煩瑣的類型名,只要可讀性好就繼續用,別用在局部變量以外的地方
- C++11 中,若變量被聲明成 auto, 那它的類型就會被自動匹配成初始化表達式的類型
- 代碼要避免無所謂的重複
- auto 只能用在局部變量裏用。別用在文件做用域變量,命名空間做用域變量和類數據成員裏。永遠別列表初始化 auto 變量
- auto 還能夠和 C++11 特性「尾置返回類型(trailing return type)」一塊兒用,不事後者只能用在 lambda 表達式裏
- 初始化列表
- C++11 中,該特性獲得進一步的推廣,任何對象類型均可以被列表初始化
- 用戶自定義類型也能夠定義接收 std::initializer_list
的構造函數和賦值運算符,以自動列表初始化
- 列表初始化也適用於常規數據類型的構造,哪怕沒有接收 std::initializer_list
的構造函數
- Lambda表達式
- 適當使用 lambda 表達式。別用默認 lambda 捕獲,全部捕獲都要顯式寫出來
- Lambda 表達式是建立匿名函數對象的一種簡易途徑,經常使用於把函數當參數傳
- Lambdas, std::functions 和 std::bind 能夠搭配成通用回調機制(general purpose callback mechanism);寫接收有界函數爲參數的函數也很容易了
- 按 format 小用 lambda 表達式怡情。
- 禁用默認捕獲,捕獲都要顯式寫出來。打比方,比起 = {return x + n;}, 您該寫成 n {return x + n;} 纔對,這樣讀者也好一眼看出 n 是被捕獲的值。
- 匿名函數始終要簡短,若是函數體超過了五行,那麼還不如起名(acgtyrant 注:即把 lambda 表達式賦值給對象),或改用函數。
- 若是可讀性更好,就顯式寫出 lambd 的尾置返回類型,就像auto.
- 模板編程
- 不要使用複雜的模板編程
- 模板編程指的是利用c++ 模板實例化機制是圖靈完備性, 能夠被用來實現編譯時刻的類型判斷的一系列編程技巧
- 模板編程的優缺點
- Boost庫
- C++11
- 適當用 C++11(前身是 C++0x)的庫和語言擴展,在貴項目用 C++11 特性前三思可移植性
命名規約
- 最重要的一致性規則是命名管理.
- 類型, 變量, 函數, 常量, 宏, 等等, 甚至. 咱們大腦中的模式匹配引擎很是依賴這些命名規則.
- 命名規約的一致性更重要, 因此不管你認爲它們是否重要, 規則總歸是規則.
- 通用命名規則
- 函數命名, 變量命名, 文件命名要有描述性; 少用縮寫.
- 儘量使用描述性的命名, 別心疼空間, 畢竟相比之下讓代碼易於新讀者理解更重要. 不要用只有項目開發者能理解的縮寫, 也不要經過砍掉幾個字母來縮寫單詞.
- 文件命名
- 文件名要所有小寫, 能夠包含下劃線 () 或連字符 (-), 依照項目的約定. 若是沒有約定, 那麼 「」 更好.
- 類型命名
- 類型名稱的每一個單詞首字母均大寫, 不包含下劃線: MyExcitingClass, MyExcitingEnum.
- 全部類型命名 —— 類, 結構體, 類型定義 (typedef), 枚舉, 類型模板參數 —— 均使用相同約定, 即以大寫字母開始, 每一個單詞首字母均大寫, 不包含下劃線.
- 變量命名
- 變量 (包括函數參數) 和數據成員名一概小寫, 單詞之間用下劃線鏈接.
- 類的成員變量如下劃線結尾, 但結構體的就不用, 如: a_local_variable, a_struct_data_member, a_class_data_member_.
- 普通變量一概小寫
- 無論是靜態的仍是非靜態的, 結構體數據成員均可以和普通變量同樣, 不用像類那樣接下劃線
- 常量命名
- 聲明爲 constexpr 或 const 的變量, 或在程序運行期間其值始終保持不變的, 命名時以 「k」 開頭, 大小寫混合.
- 函數命名
- 常規函數使用大小寫混合, 取值和設值函數則要求與變量名匹配
- 通常來講, 函數名的每一個單詞首字母大寫 (即 「駝峯變量名」 或 「帕斯卡變量名」), 沒有下劃線. 對於首字母縮寫的單詞, 更傾向於將它們視做一個單詞進行首字母大寫 (例如, 寫做 StartRpc() 而非 StartRPC()).
- 命名空間命名
- 命名空間以小寫字母命名.
- 最高級命名空間的名字取決於項目名稱.
- 要注意避免嵌套命名空間的名字之間和常見的頂級命名空間的名字之間發生衝突.
- 注意 不使用縮寫做爲名稱 的規則一樣適用於命名空間. 命名空間中的代碼極少須要涉及命名空間的名稱, 所以沒有必要在命名空間中使用縮寫.
- 枚舉命名
- 枚舉的命名應當和 常量 或 宏 一致: kEnumName 或是 ENUM_NAME.
- 單獨的枚舉值應該優先採用 常量 的命名方式. 但 宏 方式的命名也能夠接受.
- 宏命名
- 宏命名像這樣命名: MY_MACRO_THAT_SCARES_SMALL_CHILDREN.
- 一般 不該該 使用宏. 若是不得不用, 其命名像枚舉命名同樣所有大寫, 使用下劃線
- 感受 Google 的命名約定很高明, 好比寫了簡單的類 QueryResult, 接着又能夠直接定義一個變量 query_result, 區分度很好; 再次, 類內變量如下劃線結尾, 那麼就能夠直接傳入同名的形參, 好比 TextQuery::TextQuery(std::string word) : word_(word) {} , 其中 word_ 天然是類內私有成員.
註釋
- 註釋雖然寫起來很痛苦, 但對保證代碼可讀性相當重要.
- 註釋當然很重要, 但最好的代碼應當自己就是文檔. 有意義的類型名和變量名, 要遠賽過要用註釋解釋的含糊不清的名字.
- 註釋風格
- 文件註釋:
- 在每一個文件開頭加入版權公告, 文件註釋描述了該文件的內容. 若是一個文件只聲明, 或實現, 或測試了一個對象, 而且這個對象已經在它的聲明處進行了詳細的註釋, 那麼就不必再加上文件註釋. 除此以外的其餘文件都須要文件註釋.
- 不要在 .h 和 .cc 之間複製註釋, 這樣的註釋偏離了註釋的實際意義.
- 類註釋:
- 每一個類的定義都要附帶一份註釋, 描述類的功能和用法, 除非它的功能至關明顯.
- 描述類用法的註釋應當和接口定義放在一塊兒, 描述類的操做和實現的註釋應當和實現放在一塊兒.
- 函數註釋:
- 函數聲明處的註釋描述函數功能; 定義處的註釋描述函數實現.
- 基本上每一個函數聲明處前都應當加上註釋, 描述函數的功能和用途. 只有在函數的功能簡單而明顯時才能省略這些註釋(例如, 簡單的取值和設值函數).
- 讓代碼自文檔化.
- 注意標點, 拼寫和語法; 寫的好的註釋比差的要易讀的多.
- TODO註釋風格
- 關於註釋風格, 不少 C++ 的 coders 更喜歡行註釋, C coders 或許對塊註釋依然情有獨鍾, 或者在文件頭大段大段的註釋時使用塊註釋;
- 文件註釋能夠炫耀你的成就, 也是爲了捅了簍子別人能夠找你;
- 註釋要言簡意賅, 不要拖沓冗餘, 複雜的東西簡單化和簡單的東西複雜化都是要被鄙視的;
- 對於 Chinese coders 來講, 用英文註釋仍是用中文註釋, it is a problem, 但無論怎樣, 註釋是爲了讓別人看懂, 難道是爲了炫耀編程語言以外的你的母語或外語水平嗎;
- 註釋不要太亂, 適當的縮進纔會讓人樂意看. 但也沒有必要規定註釋從第幾列開始 (我本身寫代碼的時候總喜歡這樣), UNIX/LINUX 下還能夠約定是使用 tab 仍是 space, 我的傾向於 space;
- TODO 很不錯, 有時候, 註釋確實是爲了標記一些未完成的或完成的不盡如人意的地方, 這樣一搜索, 就知道還有哪些活要幹, 日誌都省了.
格式
- 每一個人均可能有本身的代碼風格和格式, 但若是一個項目中的全部人都遵循同一風格的話, 這個項目就能更順利地進行. 每一個人未必能贊成下述的每一處格式規則, 並且其中的很多規則須要必定時間的適應, 但整個項目服從統一的編程風格是很重要的, 只有這樣才能讓全部人輕鬆地閱讀和理解代碼.
- 行長度:
- 儘可能不使用非 ASCII 字符, 使用時必須使用 UTF-8 編碼.
- 咱們使用空格縮進. 不要在代碼中使用製表符. 你應該設置編輯器將製表符轉爲空格.
- 使用好的參數名.
- 只有在參數未被使用或者其用途很是明顯時, 才能省略參數名.
- 若是返回類型和函數名在一行放不下, 分行.
- 若是返回類型與函數聲明或定義分行了, 不要縮進.
- 左圓括號老是和函數名在同一行.
- 函數名和左圓括號間永遠沒有空格.
- 圓括號與參數間沒有空格.
- 左大括號總在最後一個參數同一行的末尾處, 不另起新行.
- 右大括號老是單獨位於函數最後一行, 或者與左大括號同一行.
- 右圓括號和左大括號間老是有一個空格.
- 全部形參應儘量對齊.
- 缺省縮進爲 2 個空格.
- 換行後的參數保持 4 個空格的縮進.
- 水平留白的使用根據在代碼中的位置決定. 永遠不要在行尾添加沒意義的留白.