2.我使用的C/C++編寫規範之命名約定
?
最重要的一致性規則是命名管理,命名風格直接可以直接確定命名實體是:類型、變量、函數、常量、宏等等,無需查找實體聲明,我們大腦中的模式匹配引擎依賴於這些命名規則。
命名規則具有一定隨意性,但相比按個人喜好命名,一致性更重要,所以不管你怎麽想,規則總歸是規則。
<br>
1.?通用命名規則
?
1.1 標識符的命名要清晰、明了,有明確含義,同時使用完整的單詞或大家基本可以理解的縮寫,避免使人產生誤解。
說明:盡可能給出描述性名稱,不要節約空間,讓別人很快理解你的代碼更重要。
好的命名示例:
int num_errors; // Good. int num_completed_connections; // Good.
不好的命名,使用模糊的縮寫或隨意的字符:
int n; // Bad - meaningless.
int nerr; // Bad - ambiguous abbreviation.
int n_comp_conns; // Bad - ambiguous abbreviation.
1.2 除了常見的通用縮寫以外,不使用單詞縮寫,不得使用漢語拼音。
說明:較短的單詞可通過去掉“元音”形成縮寫,較長的單詞可取單詞的頭幾個字母形成縮寫,一些單詞有大家公認的縮寫,常用單詞的縮寫必須統一。協議中的單詞的縮寫與協議保持一致。對於某個系統使用的專用縮寫應該在註釋或者某處做統一說明。
全名 | 縮寫 | 全名 | 縮寫 | 全名 | 縮寫 |
---|---|---|---|---|---|
argument | arg | maximum | max | initialize | init |
buffer | buff | message | msg | temp | tmp |
clock | clk | minimum | min | increment | inc |
command | cmd | parameter | para | synchronize | sync |
compare | cmp | previous | prev | hexadecimal | hex |
configuration | cfg | register | reg | statistic | stat |
device | dev | semaphore | sem | error | err |
1.3 用正確的反義詞組命名具有互斥意義的變量或相反動作的函數等。
示例 | 示例 | 示例 |
---|---|---|
add/remove | begin/end | create/destroy |
insert/delete | first/last | get/release |
increment/decrement | put/get | add/delete |
lock/unlock | open/close | min/max |
old/new | start/stop | next/previous |
source/target | show/hide | send/receive |
source/destination | copy/paste | up/down |
? ?
1.4 盡量避免名字中出現數字編號,除非邏輯上的確需要編號。
? ? ? ?示例:如下命名,使人產生疑惑。
#define EXAMPLE_0_TEST_
#define EXAMPLE_1_TEST_
應改為有意義的單詞命名:
#define EXAMPLE_UNIT_TEST_
#define EXAMPLE_ASSERT_TEST_
?
1.5 標識符前不應添加模塊、項目、產品、部門的名稱作為前綴。
說明:很多已有代碼中已經習慣在文件名中增加模塊名,這種寫法類似匈牙利命名法,導致文件名不可讀,並且帶來帶來如下問題:
1)第一眼看到的是模塊名,而不是真正的文件功能,阻礙閱讀;
2)文件名太長;
3)文件名和模塊綁定,不利於維護和移植。若foo.c進行重構後,從a模塊挪到b模塊,若foo.c中有模塊名,則需要將文件名從a_module_foo.c改為b_module_foo.c。
?
1.6 平臺/驅動等適配代碼的標識符命名風格保持和平臺/驅動一致。
? ? ? ?說明:涉及到外購芯片以及配套的驅動,這部分的代碼變動(包括為產品做適配的新增代碼),應該保持原有的風格。
?
1.7 重構/修改部分代碼時,應保持和原有代碼的命名風格一致。
? ? ? ?說明:根據源代碼現有的風格繼續編寫代碼,有利於保持總體一致。
? ?
? ?
2.文件命名
因為不同系統對文件名大小寫處理會不同(如MS的DOS、Windows系統不區分大小寫,但是Linux系統則區分),文件名要全部小寫,可以包含下劃線(_)或短線(-),按項目約定來。
可接受的文件命名:
my_useful_class.cpp
my-useful-class.cpp
myusefulclass.cpp
C++文件以.cpp結尾,頭文件以.h結尾。
不要使用已經存在於/usr/include下的文件名(對 UNIX、Linux 等系統而言), 如 db.h。
通常,盡量讓文件名更加明確,http_server_logs.h 就比 logs.h 要好,定義類時文件名一般成對出現,如 foo_bar.h 和 foo_bar.cpp,對應類 FooBar。
內聯函數必須放在.h 文件中,如果內聯函數比較短,就直接放在.h 中。如果代碼比較長,可以放到以-inl.h 結尾的文件中。對於包含大量內聯代碼的類,可以有三個文件:
url_table.h // The class declaration.
url_table.cc // The class definition.
url_table-inl.h // Inline functions that include lots of code.
?
?
3.類型命名
類型命名每個單詞以大寫字母開頭,不包含下劃線:MyExcitingClass、MyExcitingEnum。
所有類型命名,包括類、結構體、類型定義(typedef)與枚舉都使用相同約定,例如:
// classes and structs
class UrlTable {
class UrlTableTester {
struct UrlTableProperties {
// typedefs
typedef hash_map<UrlTableProperties *, string> PropertiesMap;
// enums
enum UrlTableErrors {
?
?
4.變量命名
????采用UNIX風格。變量名一律小寫,單詞間以下劃線相連,類的成員變量以下劃線結尾,如
my_exciting_local_variable、my_exciting_member_variable_。
????使用名詞或者形容詞+名詞方式命名變量。
??
4.1 普通變量命名
????舉例:
string table_name; // OK - uses underscore.
string tablename; // OK - all lowercase.
string tableName; // Bad - mixed case.
4.2 類數據成員
????結構體的數據成員可以和普通變量一樣,不用像類那樣接下劃線:
struct UrlTableProperties {
string name;
int num_entries;
}
?
4.3 全局變量與靜態變量
????全局變量以 g_ 為前綴。
????靜態變量以s_ 為前綴。
????說明:增加g_前綴或者s_前綴,原因如下:
????首先,全局變量十分危險,通過前綴使得全局變量更加醒目,促使開發人員對這些變量的使用更加小心。
????其次,從根本上說,應當盡量不使用全局變量,增加g_和s_前綴,會使得全局變量的名字顯得很醜陋,從而促使開發人員盡量少使用全局變量。
?
4.4 禁止使用單字節命名變量,但允許定義i、j、k作為局部循環變量。
?
4.5 禁止使用匈牙利命名法。
????說明:變量命名需要說明的是變量的含義,而不是變量的類型。在變量命名前增加類型說明,反而降低了變量的可讀性;更麻煩的問題是,如果修改了變量的類型定義,那麽所有使用該變量的地方都需要修改。
????匈牙利命名法源於微軟,然而卻被很多人以訛傳訛的使用。而現在即使是微軟也不再推薦使用匈牙利命名法。歷來對匈牙利命名法的一大詬病,就是導致了變量名難以閱讀,這和本規範的指導思想也有沖突,所以本規範特意強調,變量命名不得采用匈牙利命名法,而應該想法使變量名為一個有意義的詞或詞組,方便代碼的閱讀。
??
??
5.常量命名
????在名稱前加 k,例如:kDaysInAWeek。
????所有編譯時常量(無論是局部的、全局的還是類中的)和其他變量保持些許區別,k 後接大寫字母開頭的單詞:
const int kDaysInAWeek = 7;
?
?
6.函數命名
????函數命名應以函數要執行的動作命名,一般采用動詞或者動詞+名詞的結構。
????示例:找到當前進程的當前目錄
DWORD GetCurrentDirectory( DWORD BufferLength, LPTSTR Buffer );
函數指針除了前綴,其他按照函數的命名規則命名。
普通函數(regular functions,這裏與訪問函數等特殊函數相對)大小寫混合,存取函數(accessors and mutators)則要求與變量名匹配:MyExcitingFunction()、MyExcitingMethod()、my_exciting_member_variable()、set_my_exciting_member_variable()。
?
6.1 普通函數
????函數名以大寫字母開頭,每個單詞首字母大寫,沒有下劃線:
????AddTableEntry()
????DeleteUrl()
?
6.2 存取函數
????存取函數要與存取的變量名匹配,這兒摘錄一個擁有實例變量 num_entries_的類:
class MyClass {
public:
...
int num_entries() const { return num_entries_; }
void set_num_entries(int num_entries) { num_entries_ = num_entries; }
private:
int num_entries_;
};
其他短小的內聯函數名也可以使用小寫字母,例如,在循環中調用這樣的函數甚至都不需要緩存其值,小寫命名就可以接受。
?
?
7.命名空間
?命名空間的名稱是全小寫的,其命名基於項目名稱和目錄結構:google_awesome_project。
?
?
8.枚舉命名
????枚舉值應全部大寫,單詞間以下劃線相連:MY_EXCITING_ENUM_VALUE。
????枚舉名稱屬於類型,因此大小寫混合:UrlTableErrors。
enum UrlTableErrors {
OK = 0,
ERROR_OUT_OF_MEMORY,
ERROR_MALFORMED_INPUT,
};
?
?
9.宏命名
????采用全大寫字母,單詞之間加下劃線“_”的方式命名。例如:
????MY_MACRO_THAT_SCARES_SMALL_CHILDREN\par
????除了頭文件或編譯開關等特殊標識定義,宏定義不能使用下劃線“_”開頭和結尾。
?
(未完待續)
2.我使用的C/C++編寫規範之命名約定