程式碼中變數的命名方法
1、引言
隨著計算機技術的不斷髮展,計算機計算能力的提升催生了大量大型軟體的出現,大型軟體的程式碼量動輒成千上萬行,甚至數十萬行。隨著程式碼量的指數級增長,以前未曾注意的“小”問題也明顯被放大。比如程式碼中的變數命名,這屬於我們印象中的“小”問題,對於程式碼量小的程式來說,將變數命名為a、b、aa、string1、string2等型別,並不會影響程式的編寫及閱讀,如果是程式碼量大的程式,如果通篇都是字母、*1、*2等型別的變數名稱,不僅在編寫程式碼時容易出錯,而且極不利於程式的閱讀,那程式的後期維護就更難上加難了!所以如何有效地解決這些“小”問題也成了亟需研究的內容。
本文主要研究的是在程式碼編寫時的變數、函式命名法。目前存在的主流命名法主要有匈牙利命名法、駱駝命名法、帕斯卡命名法。下面就對這三種命名法進行詳細的介紹,並結合三種命名法的特點提出適合自己的命名規則。
2、匈牙利命名法
2.1、簡介
匈牙利命名法(Hungarian Notation),是由1972年至1981年在施樂公司工作的程式設計師查爾斯.西蒙尼(Charles.Simony),此人後來成為微軟的總設計師,因其祖籍是匈牙利,故有此名。
匈牙利命名法在國內之所以這麼有名是因為當時微軟對其推崇備至。在上世紀90年代,MFC的出現影響了一代代程式設計師,而MFC中各種類的命名是以匈牙利命名法命名的,再加上當時微軟出了不錯的書《Windows程式設計》推波助瀾,而同時呢,國內UNIX程式設計風格氛圍不強,這種命名法幾乎成了國內變數命名法的標準。這就導致在現在的某些書籍或者專案中推薦使用匈牙利命名法
2.2、規則
匈牙利命名法的基本規則是:變數名=屬性+型別+物件描述,其中每一個物件的名稱都要求有明確含義,可以是物件名字全程或者一部分,同是要基於容易記憶理解的原則。
變數名中各部分的使用規範:
1) 屬性部分
變數名的屬性主要是表明該變數的屬性,比如變數的作用範圍(全域性\區域性)、成員變數、或者靜態變數等。相關的表示如下:
全域性變數 |
g_ |
常量 |
c_ |
類的成員變數 |
m_ |
靜態變數 |
s_ |
2) 型別部分
型別值得是變數的型別,如整型、浮點型、字串等。部分表示如下:
陣列 |
a |
長整型 |
l |
指標 |
p |
布林型 |
b |
函式 |
fn |
浮點型 |
f |
無效 |
v |
雙位元組 |
dw |
控制代碼 |
h |
字串 |
sz |
短整型 |
n |
雙精度浮點型 |
d |
計數 |
cnt |
字元 |
ch |
整型 |
i |
位元組 |
by |
位元組 |
w |
無符號 |
u |
3) 描述部分
描述部分通常用來表示該變數描述的意義,即該變數所表示的含義,部分標識如下:
最大 |
Max |
最小 |
Min |
初始化 |
Init |
臨時變數 |
Temp |
源物件 |
Src |
目的物件 |
Dest |
4) 例子
變數定義的這些描述符號可以多個同時使用,順序一般是m_,再指標,再簡單資料型別,再其它。
hwnd: h型別描述,表示控制代碼;wnd是變數的物件描述,表示視窗,所以hwnd表示視窗控制代碼。
pfnEatApple: pfn是型別描述,表示指向函式的指標;EatApple是變數物件描述,所以pfnEatApple表示指向EatApple函式的函式指標變數。
m_lpszStr: m_表示是成員變數;l表示長整型;p表示指標;sz表示的是字串;Str是物件描述;所以m_lpszStr的含義就是表示指向一個字串的長指標成員變數。
由此可見,匈牙利命名法通過在變數名前面加上相應的小寫字母的符號標識作為字首,標識出變數的作用域;字首之後的是首字母大寫的一個單詞或單詞組合,主要指明變數的用途
2.3、匈牙利命名法存在的問題
匈牙利命名法是最有名但也是最有爭議的一種命名方法。隨著軟體程式碼量的增加以及整合開發環境功能越來越強大,匈牙利命名法存在的問題也越來越突出。
2.3.1、HN命名法並不能幫助編譯器進行型別檢查也不加快開發速度
匈牙利命名法與其他命名法相比最主要的特點就是在變數名中指定了該變數的型別,在編譯器功能還不是很強大的年代,這種命名法確實有它獨到的優勢。
但是隨著編譯器功能越來越強大,在編寫程式碼時,如果需要的話是可以顯示變數型別的,而且最主要也是把匈牙利命名法推下神壇的就是現代的整合開發環境都具有自動標記不匹配的型別的功能。
匈牙利命名法在編譯器做型別檢查時是多餘的。特別是對於C++這樣的強型別語言,一個提供型別檢查的語言在確定一個變數與其型別一致時,比人眼僅僅檢查變數的用法與變數名一致要強大得多
2.3.2、HN命名法保持字首不利於程式碼重構
在程式碼的重構中,如果一個變數的型別改變了,那麼對於該變數而言需要把所有的該變數名修改,因為該變數是把變數型別與變數名捆綁在一起 ,這樣極不利於程式碼的移植。
一個眾所周知的例子就是WPARAM型別,以及在許多Windows系統函式宣告中使用的wParam引數。它原本是一個16位的型別(w描述的是Word型別),但在後來的作業系統中被改成了32位或64位,但仍保留原來的名字
2.3.3、HN命名法保持型別字首會造成一定的冗餘成本
HN命名法中,變數將型別從單一地點(變數宣告處)複製到了多個地點(變數使用處),這會造成一定的冗餘成本,其一就是前面提到的維護程式碼一致性的難題;其二就是佔用了額外的空間與時間;空間是指為了保留這些含有變數型別的變數需要佔用額外的程式碼行數,因為這種命名法不可避免的會造成變數名長度的增加;時間是指,在閱讀程式碼時每當看到變數總是先去解析變數的型別,然後才會解析變數所代表的含義,這種“拐個彎”的想法總會造成在閱讀程式碼時時間上的增加。比如定義了一個變數m_lpszName,我們首先回去解析m_lpsz所代表的含義,然後才知道原來這個變數代表的是名字。
在比如常見的字串複製函式strcpy(pstrSource, pstrDest); 程式設計師需要從變數名中剔除pstr之類的字首才能找到Source、Dest,才能理解變數的含義。相比strcpy(Source, Dest); 由於strcpy函式本身它已經規定了引數的型別,對於程式設計師來說只要一看到這個函式就會知道這兩個引數的型別,所以,大部分情況下是沒有必要按照HN命名法為變數命名的,也能避免一些不必要的冗餘
3、駱駝命名法
3.1、簡介
駱駝式命名法(CamelCase),又稱駝峰命名法。正如名稱CamelCase所表示的形式,是指混合使用大小寫字母來構成變數和函式的名字。
駝峰命名法就是以單個單詞或多個單片語成變數或者函式的唯一識別符號時,第一個單詞以小寫字母開始,第二個單詞以及後面的每一個單詞的首字母大寫,例如myFirstName、myLastName,這樣的變數名看上去就像駱駝峰一樣此起披伏,故此得名。
需要注意的是這些單片語成的識別符號必須具有一定的意義,比如說:int studentNum; 通過變數名就能直觀的看出變數所代表的意義,就學生數量,而程式設計師也可以根據變數名的意義大致猜測出變數型別,就向studentNum變數,既然是指學生數量,那肯定是整型資料了。
駝峰法有分小駝峰法、大駝峰法;
小駝峰法大多是用來標識變數,是駝峰法的常規用法,即第一個字母小寫,其他單詞首字母大寫,例如:
int myStudentCount;
大駝峰法又稱帕斯卡命名法,是把變數名稱的第一個字母也大寫。主要用於類名、函式名、屬性、名稱空間等,例如:
class DataBaseUser;
void GetUserName();
4、帕斯卡命名法
帕斯卡(Pascal)命名法又稱大駝峰法,用法見上文
5、適合自己的命名法
匈牙利命名法、駝峰命名法、帕斯卡命名法皆是針對程式碼編寫時為了提高編碼質量和效率而提出的一種變數命名規範,這三種命名規範既有優點也有缺點,不能只使用著一種命名規範,要根據相關情況綜合使用這三種命名規範,主要目的還是為了是變數名便於記憶識別。下面就根據我的相關經驗與認識談談我自己的命名規範
5.1、Persional Notation
1) 變數的命名使用小駝峰法;函式、型別名等非常規變數採用大駝峰法;這也是我目前已經採用的方法;
2) 匈牙利命名法中關於變數屬性的用法是可取的;在實際編寫程式碼時回不可避免的用到全域性變數,而在閱讀時,往往無法識別出全域性變數,總是用上下文查詢的方法,這樣很不方便,參考HN命名法中關於變數屬性的使用,覺得在變數命名中引入屬性的概念是很有幫助的。
全域性變數 |
g_ |
常量 |
c_ |
類的成員變數 |
m_ |
靜態變數 |
s_ |
3) HN命名法中關於指標的用法。在定義變數時加上p_的字首;
4) 中間變數加上Temp字尾;如airTemp
5) 對於作用範圍很小的變數,比如for迴圈中的漸變變數,可以使用極簡形式的變數如i、j等 ;
6) 對於C++STL中型別的變數,比如map、vector、list等,在宣告變數時加上對應型別的字尾,如Map、Vector、List。如airMessageMap
7) 對於執行緒函式,加上Thread字尾;如ServerThread()