1. 程式人生 > >程式設計規範(一):C/C++的命名原則

程式設計規範(一):C/C++的命名原則


無以規矩,不成方圓。
符合規範的統一命名是程式編寫的基本規矩之一。很多時候我們不願意接手別人的程式碼,原因之一就是程式碼命名很亂;我們自己寫程式碼時經常寫到後面忘了前面,也有可能是我們沒有養成規範的命名習慣。當寫程式碼成為一種藝術的美時,這種美的最直接的體現就是其中變數函式等命名的規範性。

基本的命名原則

首先總結一下命名的基本原則,也就是“道”的層次。

方面 要求
同一性 一個方面是整個檔案中命名的原則要相同,如變數、函式都按照相同的原則命名;另一方面是一個子模組或派生類中,要遵循其基類或整體模組的命名風格,保持命名風格在整個模組中的同一性。
識別符號組成 命名應該由識別符號組成,組成部分要確定,如變數型別字首+變數資訊英文縮寫,且縮寫統一採用動賓格式。
最小化長度AND最大化資訊量原則 在保持一個識別符號意思明確的同時,應當儘量縮短其長度。
避免在不同作用域中重名 程式中不要出現名字完全相同的區域性變數和全域性變數,儘管兩者的作用域不同而不會發生語法錯誤,但容易使人誤解。
正確命名具有互斥意義的識別符號 用正確的反義片語命名具有互斥意義的識別符號,如:“nMinValue"和"nMaxValue”,“GetName()” 和 “SetName()” …
避免名字中出現數字編號 儘量避免名字中出現數字編號,如Value1,Value2等,除非邏輯上的確需要編號。因為數字並傳達不了有用資訊。
禁止取單個字元作為變數名 i 、j 、k 作區域性迴圈變數是允許的,其他則不允許。因為其很容易敲錯(如i寫成j),而編譯時又檢查不出來。
說明特殊約定或縮寫 在原始檔的開始之處,對檔案中所使用的縮寫或約定,特別是特殊的縮寫,進行必要的註釋說明。
特殊命名 除了編譯開關/ 標頭檔案等特殊應用,應避免使用_EXAMPLE_TEST_ 之類以下劃線開始和結尾的定義。

常見的命名方法

目前業界共有四種常見的命名法則:駝峰命名法、匈牙利命名法、帕斯卡命名法和下劃線命名法,其中前三種是較為流行的命名法。

駝峰命令法

正如它的名稱所表示的那樣,是指混合使用大小寫字母來構成變數和函式的名字,其中第一個單詞的首字母小寫,其他單詞的首字母大寫,大寫字母的位置如駝峰一樣交替出現。下面是分別用駱駝式命名法和下劃線法命名的同一個函式:

printEmployeePaychecks
()print_employee_paychecks()

第一個函式名使用了駝峰命名法,函式名中的每一個邏輯斷點都有一個大寫字母來標記。第二個函式名使用了下劃線法,函式名中的每一個邏輯斷點都有一個下劃線來標記。駝峰命名法近年來越來越流行了,在許多新的函式庫和Microsoft Windows這樣的環境中,它使用得當相多。另一方面,下劃線法是C出現後開始流行起來的,在許多舊的程式和UNIX這樣的環境中,它的使用非常普遍。

匈牙利命名法

廣泛應用於象Microsoft Windows這樣的環境中。Windows 程式設計中用到的變數(還包括巨集)的命名規則為匈牙利命名法,這種命名技術是由一位能幹的 Microsoft 程式設計師查爾斯-西蒙尼(Charles Simonyi) 提出的。
匈牙利命名法通過在變數名前面加上相應的小寫字母的符號標識作為字首,標識出變數的作用域、型別等。這些符號可以多個同時使用,順序是先m_(成員變數)、再指標、再簡單資料型別、再其它。這樣做的好處在於能增加程式的可讀性,便於對程式的理解和維護。
例如:m_lpszStr, 表示指向一個以0字元結尾的字串的長指標成員變數。
匈牙利命名法關鍵是:識別符號的名字以一個或者多個小寫字母開頭作為字首;字首之後的是首字母大寫的一個單詞或多個單詞組合,該單詞要指明變數的用途。

帕斯卡(pascal)命名法

與駝峰命名法類似,二者的區別在於:駝峰命名法是首字母小寫,而帕斯卡命名法是首字母大寫,如:

DisplayInfo();
string UserName;

二者都是採用了帕斯卡命名法。

三種命名規則的小結

MyData就是一個帕斯卡命名的示例;myData是一個駝峰命名法,它第一個單詞的第一個字母小寫,後面的單詞首字母大寫,看起來像一個駱駝;iMyData是一個匈牙利命名法,它的小寫的i說明了它的型態,後面的和帕斯卡命名相同,指示了該變數的用途。

命名規範

現在討論命名的具體操作,即“術”的層次。C++命名要採用匈牙利命名法,即要包括引數的型別資訊。現在有很多人認為如今的IDE都提供了識別變數型別的功能,在變數命中體現變數型別屬於畫蛇添足的做法。以前我就被這種觀點給洗腦了,結果在看程式的時候速度特別慢,每看到一個變數都要用滑鼠放在其上面獲取其變數型別!這時我才意識到:如果直接把變數型別放在變數名稱中,就可以很大的提升看程式碼的速度和體驗。因此,我認為命名要採用匈牙利法。

類/結構命名方法

除了異常類等個別情況(不希望使用者把該類看作一個普通的、正常的類之情況)外,C++類/結構 的命名應該遵循以下準則1

準則 解釋
C++類/結構的命名 類的名稱都要以大寫字母“C”開頭,後跟一個或多個單詞。為便於界定,每個單詞的首字母要大寫。
推薦的組成形式 類的命名推薦用"名詞"或"形容詞+名詞"的形式,例如:“CAnalyzer”, “CFastVector” …
傳統C結構體的命名 傳統C結構體的名稱全部由大寫字母組成,單詞間使用下劃線界定,例如:“SERVICE_STATUS”, “DRIVER_INFO” …

不同於C++類的概念,傳統的C結構體只是一種將一組資料捆綁在一起的方式。

函式命名方法

函式的命名應該儘量用英文(或英文縮寫、中文全拼、中文全拼縮寫)表達出函式完成的功能——函式名應準確描述函式的功能。遵循動賓結構的命名法則,函式名中動詞在前,並在命名前加入函式的字首,函式名的長度不得少於8個字母。函式名首字大寫,若包含有兩個單詞的每個單詞首字母大寫。如果是OOP 方法,可以只有動詞(名詞是物件本身)。

函式的命名 函式的名稱由一個或多個單片語成。為便於界定,每個單詞的首字母要大寫。
推薦的組成形式 函式名應當使用"動詞"或者"動詞+名詞"(動賓片語)的形式。例如:“GetName()”, “SetValue()”, “Erase()”, “Reserve()” …
保護成員函式 保護成員函式的開頭應當加上一個下劃線“_”以示區別,例如:"_SetState()" …
私有成員函式 類似地,私有成員函式的開頭應當加上兩個下劃線“__”,例如:"__DestroyImp()" …
虛擬函式 虛擬函式習慣以“Do”開頭,如:“DoRefresh()”, “_DoEncryption()” …
回撥和事件處理函式 回撥和事件處理函式習慣以單詞“On”開頭。例如:"_OnTimer()", “OnExit()” …

變數命名原則

變數的命名規則要求用“匈牙利法”,即開頭字母用變數的型別,其餘部分用變數的英文意思、英文的縮寫、中文全拼或中文全拼的縮寫,要求單詞的第一個字母應大寫。即: 變數名=作用域字首+變數型別+變數的英文意思(或英文縮寫、中文全拼、中文全拼縮寫)。對非通用的變數,在定義時加入註釋說明,變數定義儘量可能放在函式的開始處。
作用域字首標明一個變數的可見範圍。作用域可以有如下幾種:

字首 說明
區域性變數
m_ 類成員變數(member)
sm_ 靜態類成員變數(static member)
g_ 全域性變數(global)
s_ 靜態變數(static)
sg_ 靜態全域性變數(static gloabl)
gg_ 程序間共享的共享資料段全域性變數(global global)
c_ 常量變數(const)

型別字首標明一個變數的型別,可以有如下幾種:

字首 說明
i 整數型別int
n 短整數型別short int
l 長整數型別long int
c 字元型別char
b 布林型變數bool
f 單浮點型變數float
d 爽浮點型變數double
by 無符號字元unsigned char
w 無符號整型unsigned int(WORD)
s 字串string
sz 用0結尾的字串
p 指標變數,同理pp代表二重指標pointer

變數的英文意思,一般採用動詞+賓語,或者形容詞+名詞進行表示。

函式引數命名規範2

  • 引數名稱的命名參照變數命名規範。
  • 為了提高程式的執行效率,減少引數佔用的堆疊,傳遞大結構的引數,一律採用指標或引用方式傳遞。
  • 為了便於其他程式設計師識別某個指標引數是入口引數還是出口引數,同時便於編譯器檢查錯誤,應該在入口引數前加入const標誌。如:cmCopyString(const CHAR * c_szSource, CHAR * szDest)……

常量的命名方法

對常量(包括錯誤的編碼)命名,規則如下:常量名由型別字首+全大寫字母組成,單詞間通過下劃線來界定,如:cDELIMITER, nMAX_BUFFER …

列舉、聯合、typedef命名方法

列舉、聯合及typedef語句都是定義新型別的簡單手段,它們的命名規則為:型別字首+大寫名稱。
對列舉型別(enum)中的變數,要求用列舉變數或其縮寫做字首。並且要求用大寫。如:

enum cmEMDAYS
{
EMDAYS_MONDAY;
EMDAYS_TUESDAY;
……
};

對struct、union變數的命名要求定義的型別用大寫。並要加上字首,其內部變數的命名規則與變數命名規則一致。
結構一般用S開頭,如:

struct ScmNPoint
{
int nX;//點的X位置
int nY; //點的Y位置
};

聯合體一般用U開頭,如:

union UcmLPoint
{
LONG lX;
LONG lY;
}

感謝博文1和博文2中博主的技術分享,從中受益良多。希望今後我能夠按照自己總結的命名規範開始,開啟自己的C++進階之旅。

祝楓
2018年10月7日