Google C++程式設計風格指南(六):程式碼註釋
http://www.kuqin.com/language/20080726/12448.html
2. 檔案註釋可以炫耀你的成就,也是為了捅了簍子別人可以找你;3. 註釋要言簡意賅,不要拖沓冗餘;4. 註釋是為了讓別人看懂,難道是為了炫耀程式語言之外的你的母語或外語水平嗎;5. 註釋不要太亂,適當的縮排才會讓人樂意看……
- 註釋
註釋雖然寫起來很痛苦,但對保證程式碼可讀性至為重要,下面的規則描述了應該註釋什麼、註釋在哪兒。當然也要記住,註釋的確很重要,但最好的程式碼本身就是文件(self-documenting),型別和變數命名意義明確要比通過註釋解釋模糊的命名好得多。
註釋是為別人(下一個需要理解你的程式碼的人)而寫的,認真點吧,那下一個人可能就是你!
1. 註釋風格(Comment Style)
使用//
或/* */
,統一就好。
//
或/* */
都可以,//
只是用的更加廣泛,在如何註釋和註釋風格上確保統一。
2. 檔案註釋(File Comments)
在每一個檔案開頭加入版權公告,然後是檔案內容描述。
法律公告和作者資訊:
每一檔案包含以下項,依次是:
1) 版權(copyright statement):如Copyright 2008 Google Inc.
;
2) 許可版本(license boilerplate):為專案選擇合適的許可證版本,如Apache 2.0、BSD、LGPL、GPL;
3) 作者(author line):標識檔案的原始作者。
如果你對其他人建立的檔案做了重大修改,將你的資訊新增到作者資訊裡,這樣當其他人對該檔案有疑問時可以知道該聯絡誰。
檔案內容:
每一個檔案版權許可及作者資訊後,都要對檔案內容進行註釋說明。
通常,.h
檔案要對所宣告的類的功能和用法作簡單說明,.cc
檔案包含了更多的實現細節或演算法討論,如果你感覺這些實現細節或演算法討論對於閱讀有幫助,可以把.cc
中的註釋放到.h
中,並在.cc
中指出文件在.h
中。
不要單純在.h
和.cc
間複製註釋,複製的註釋偏離了實際意義。
3. 類註釋(Class Comments)
每個類的定義要附著描述類的功能和用法的註釋。
// Iterates over the contents of a GargantuanTable. Sample usage: // GargantuanTable_Iterator* iter = table->NewIterator(); // for (iter->Seek("foo"); !iter->done(); iter->Next()) { // process(iter->key(), iter->value()); // } // delete iter; class GargantuanTable_Iterator { ... };
如果你覺得已經在檔案頂部詳細描述了該類,想直接簡單的來上一句“完整描述見檔案頂部”的話,還是多少在類中加點註釋吧。
如果類有任何同步前提(synchronization assumptions),文件說明之。如果該類的例項可被多執行緒訪問,使用時務必注意文件說明。
4. 函式註釋(Function Comments)
函式宣告處註釋描述函式功能,定義處描述函式實現。
函式宣告:
註釋於宣告之前,描述函式功能及用法,註釋使用描述式("Opens the file")而非指令式("Open the file");註釋只是為了描述函式而不是告訴函式做什麼。通常,註釋不會描述函式如何實現,那是定義部分的事情。
函式宣告處註釋的內容:
1) inputs(輸入)及outputs(輸出);
2) 對類成員函式而言:函式呼叫期間物件是否需要保持引用引數,是否會釋放這些引數;
3) 如果函式分配了空間,需要由呼叫者釋放;
4) 引數是否可以為NULL
;
5) 是否存在函式使用的效能隱憂(performance implications);
6) 如果函式是可重入的(re-entrant),其同步前提(synchronization assumptions)是什麼?
舉例如下:
// Returns an iterator for this table. It is the client's // responsibility to delete the iterator when it is done with it, // and it must not use the iterator once the GargantuanTable object // on which the iterator was created has been deleted. // // The iterator is initially positioned at the beginning of the table. // // This method is equivalent to: // Iterator* iter = table->NewIterator(); // iter->Seek(""); // return iter; // If you are going to immediately seek to another place in the // returned iterator, it will be faster to use NewIterator() // and avoid the extra seek. Iterator* GetIterator() const;
但不要有無謂冗餘或顯而易見的註釋,下面的註釋就沒有必要加上“returns false otherwise”,因為已經暗含其中了:
// Returns true if the table cannot hold any more entries. bool IsTableFull();
註釋構造/解構函式時,記住,讀程式碼的人知道構造/解構函式是什麼,所以“destroys this object”這樣的註釋是沒有意義的。說明建構函式對引數做了什麼(例如,是否是指標的所有者)以及解構函式清理了什麼,如果都是無關緊要的內容,直接省掉註釋,解構函式前沒有註釋是很正常的。
函式定義:
每個函式定義時要以註釋說明函式功能和實現要點,如使用的漂亮程式碼、實現的簡要步驟、如此實現的理由、為什麼前半部分要加鎖而後半部分不需要。
不要從.h
檔案或其他地方的函式宣告處直接複製註釋,簡要說明函式功能是可以的,但重點要放在如何實現上。
5. 變數註釋(Variable Comments)
通常變數名本身足以很好說明變數用途,特定情況下,需要額外註釋說明。
類資料成員:
每個類資料成員(也叫例項變數或成員變數)應註釋說明用途,如果變數可以接受NULL
或-1等警戒值(sentinel values),須說明之,如:
private: // Keeps track of the total number of entries in the table. // Used to ensure we do not go over the limit. -1 means // that we don't yet know how many entries the table has. int num_total_entries_;
全域性變數(常量):
和資料成員相似,所有全域性變數(常量)也應註釋說明含義及用途,如:
// The total number of tests cases that we run through in this regression test. const int kNumTestCases = 6;
6. 實現註釋(Implementation Comments)
對於實現程式碼中巧妙的、晦澀的、有趣的、重要的地方加以註釋。
程式碼前註釋:
出彩的或複雜的程式碼塊前要加註釋,如:
// Divide result by two, taking into account that x // contains the carry from the add. for (int i = 0; i < result->size(); i++) { x = (x << 8) + (*result)[i]; (*result)[i] = x >> 1; x &= 1; }
行註釋:
比較隱晦的地方要在行尾加入註釋,可以在程式碼之後空兩格加行尾註釋,如:
// If we have enough memory, mmap the data portion too. mmap_budget = max<int64>(0, mmap_budget - index_->length()); if (mmap_budget >= data_size_ && !MmapData(mmap_chunk_bytes, mlock)) return; // Error already logged.
注意,有兩塊註釋描述這段程式碼,當函式返回時註釋提及錯誤已經被記入日誌。
前後相鄰幾行都有註釋,可以適當調整使之可讀性更好:
... DoSomething(); // Comment here so the comments line up. DoSomethingElseThatIsLonger(); // Comment here so there are two spaces between // the code and the comment. ...
NULL、true/false、1、2、3……:
向函式傳入、布林值或整數時,要註釋說明含義,或使用常量讓程式碼望文知意,比較一下:
bool success = CalculateSomething(interesting_value, 10, false, NULL); // What are these arguments??
和:
bool success = CalculateSomething(interesting_value, 10, // Default base value. false, // Not the first time we're calling this. NULL); // No callback.
使用常量或描述性變數:
const int kDefaultBaseValue = 10; const bool kFirstTimeCalling = false; Callback *null_callback = NULL; bool success = CalculateSomething(interesting_value, kDefaultBaseValue, kFirstTimeCalling, null_callback);
不要:
注意永遠不要用自然語言翻譯程式碼作為註釋,要假設讀你程式碼的人C++比你強:D:
// Now go through the b array and make sure that if i occurs, // the next element is i+1. ... // Geez. What a useless comment.
7. 標點、拼寫和語法(Punctuation, Spelling and Grammar)
留意標點、拼寫和語法,寫的好的註釋比差的要易讀的多。
註釋一般是包含適當大寫和句點(.)的完整的句子,短一點的註釋(如程式碼行尾的註釋)可以隨意點,依然要注意風格的一致性。完整的句子可讀性更好,也可以說明該註釋是完整的而不是一點不成熟的想法。
雖然被別人指出該用分號(semicolon)的時候用了逗號(comma)有點尷尬。清晰易讀的程式碼還是很重要的,適當的標點、拼寫和語法對此會有所幫助。
8. TODO註釋(TODO Comments)
對那些臨時的、短期的解決方案,或已經夠好但並不完美的程式碼使用TODO
註釋。
這樣的註釋要使用全大寫的字串TODO
,後面括號(parentheses)里加上你的大名、郵件地址等,還可以加上冒號(colon):目的是可以根據統一的TODO
格式進行查詢:
// TODO(kl@gmail.com): Use a "*" here for concatenation operator. // TODO(Zeke) change this to use relations.
如果加上是為了在“將來某一天做某事”,可以加上一個特定的時間("Fix by November 2005")或事件("Remove this code when all clients can handle XML responses.")。
______________________________________
譯者:註釋也是比較人性化的約定了:
1. 關於註釋風格,很多C++的coders更喜歡行註釋,C coders或許對塊註釋依然情有獨鍾,或者在檔案頭大段大段的註釋時使用塊註釋;
2. 檔案註釋可以炫耀你的成就,也是為了捅了簍子別人可以找你;
3. 註釋要言簡意賅,不要拖沓冗餘,複雜的東西簡單化和簡單的東西複雜化都是要被鄙視的;
4. 對於Chinese coders來說,用英文註釋還是用中文註釋,it is a problem,但不管怎樣,註釋是為了讓別人看懂,難道是為了炫耀程式語言之外的你的母語或外語水平嗎;
5. 註釋不要太亂,適當的縮排才會讓人樂意看,但也沒有必要規定註釋從第幾列開始(我自己寫程式碼的時候總喜歡這樣),UNIX/LINUX下還可以約定是使用tab還是space,個人傾向於space;
6. TODO很不錯,有時候,註釋確實是為了標記一些未完成的或完成的不盡如人意的地方,這樣一搜尋,就知道還有哪些活要幹,日誌都省了。
相關文章
- Google C++ 程式設計風格指南:註釋GoC++程式設計
- Google C++程式設計風格指南GoC++程式設計
- Google C++ 程式設計風格指南:類GoC++程式設計
- Google C++ 程式設計風格指南:格式GoC++程式設計
- Google C++ 程式設計風格指南:作用域GoC++程式設計
- Google C++程式設計風格指南(七):格式GoC++程式設計
- Google C++ 程式設計風格指南:其他 C++ 特性GoC++程式設計
- Google C++程式設計風格指南(三):C++ 類GoC++程式設計
- Google C++ 程式設計風格指南:命名約定GoC++程式設計
- Google C++程式設計風格指南(二):作用域GoC++程式設計
- Google Java 程式設計風格指南GoJava程式設計
- Google C++ 程式設計風格指南:來自 Google 的奇技GoC++程式設計
- Google C++ 程式設計風格指南:標頭檔案GoC++程式設計
- Google C++程式設計風格指南(五):命名約定GoC++程式設計
- Google Python 程式設計風格指南GoPython程式設計
- Google JavaScript 程式碼風格指南GoJavaScript
- Google C++程式設計風格指南(八):規則之例外GoC++程式設計
- Google C++程式設計風格指南(四):智慧指標和其他C++特性GoC++程式設計指標
- Pycharm 程式碼註釋風格模板PyCharm
- Google Java 程式設計風格指南 —— 見微知著GoJava程式設計
- JavaScript 程式設計風格指南JavaScript程式設計
- JavaScript 程式碼風格指南JavaScript
- Vue 前端程式碼風格指南Vue前端
- [C++][程式設計風格]C++命名規則C++程式設計
- 從程式碼的風格看出六種不同型別的程式設計師型別程式設計師
- java程式設計規約----程式碼風格(一)Java程式設計
- Google JavaScript 風格指南GoJavaScript
- Eclipse中使用google程式碼風格EclipseGo
- Javascript程式設計風格JavaScript程式設計
- PEP 8 程式程式碼的編寫風格指南
- .NET框架-微軟C#程式設計風格官方指南框架微軟C#程式設計
- 前端程式碼規範 — JavaScript 風格指南前端JavaScript
- 糟糕程式設計師的程式設計風格程式設計師
- 《雲端程式碼:Google App Engine程式設計指南 》小編手記GoAPP程式設計
- 物件導向程式設計風格 VS 基於物件程式設計風格(boost::bind/function)物件程式設計Function
- bash程式設計 註釋程式設計
- 優秀Java程式設計師的程式設計風格Java程式設計師
- 程式設計師是否有義務做好程式碼的註釋?你做好程式碼註釋了嗎?程式設計師