匈牙利命名法的辯思
隨手打開8月要檢視的代碼,發現這次兩個組的代碼風格居然都選擇了匈牙利命名法。也就正好借着這個機會談談這種命名法。
由於這種命名法的深厚群眾基礎,我先套用一句小龍的說法,我說的都是錯的。請大家抱着兼聽則明的態度看這篇文章,大部分資料來自網上,我不是原創只是整理者,請參見附錄:
BTW:2006年前我自己也是一個匈牙利命名發的堅定擁護者,直到sonicmao給我打開另外一扇門。
匈牙利命名法的前世今生
匈牙利命名法,由1972年至1981年在施樂帕洛阿爾托研究中心工作的-程序員查爾斯·西蒙尼Charles Simonyi發明。此人后來成了微軟的總設計師,因為其祖籍是匈牙利(維基對這個命名有一些有趣的解釋),固有此名。
匈牙利命名法的變量名由一個或多個小寫字母開始,這些字母有助於記憶變量的類型和用途,緊跟着的就是程序員選擇的任何名稱。這個后半部分的首字母可以大寫,以區別前面的類型指示字母。而在最前面加入前綴m_,s_,g_表示變量的作用域類型。匈牙利命名法的目標便於記憶,而且使變量名清晰易懂(一看變量就知道他是什么類型的),增強了代碼的可讀性,方便各程序員之間相互交流代碼。
這個東東之所以那么流行當然拜微軟所賜,隨着MFC在90年代的燦然光輝影響了一代代程序員,再加上一些微軟出的不錯的書(比如《Windows程序設計》)推波助瀾,而同時由於國內UNIX編程風格以及辯思氛圍的不強,這個命名法幾乎成了國內變量命名法的標准。甚至很多編碼規范中會直接推薦使用匈牙利命名法。
為什么說大家的匈牙利命名其實都用錯了?
如果翻閱過《軟件隨想錄》的同學,或者喜歡維基搜索的同學就會發現,其實匈牙利命名法其實是有分支的,其包括兩個分值,匈牙利系統命名法,和匈牙利應用命名法。
匈牙利系統命名法中前綴代表了變量的實際數據類型。
匈牙利應用命名法不表示實際數據類型,而是給出了變量目的的提示,或者說它代表了什么。
其實按照查爾斯·西蒙尼論文的原意,大部分時候,前綴應該是自然語意的,也就是說應該采用匈牙利應用命名法、。
查爾斯·西蒙尼的匈牙利命名法的原型在微軟公司內部最初被叫做"應用型匈牙利命名法"(Apps Hungarian),因為它是在"應用程序部"(Applications Division)中使用的,也就是用在 Word 和 Excel 身上。在 Excel 的源碼中,你可以看到大量的 rw 和 col 。使用這種"應用型匈牙利命名法",我們可以在看到變量后很快理解其含義,並很容易發現代碼中的問題。
然而,一定程度上由於 Simonyi 自己在編寫文檔時,用了"type"這個詞,而不是"kind",於是被人誤以為 Simonyi 指的是數據類型。盡管 Simonyi 很詳細、很准確地解釋了他所說的"type"到底是什么意思。可惜於事無補,危害已經釀成了。悲劇的結果就是產生了我們現在熟悉的"系統型匈牙利命名法"(System Hungarian)。
而悲劇的是,我們今天用匈牙利命名法的基本都是匈牙利系統命名法,其實我們都背離了查爾斯·西蒙尼的想法。
關於匈牙利(系統)命名法辯思
匈牙利(系統)命名法的最大好處就是你一看到一個變量名稱就會立即知道它的類型,當然它也是有很多問題。
類型的縮寫並不靠譜
因為沒有統一的類型縮寫規范,而且C++代碼達到一定規模的時候。名稱的沖突也是很大的。比如str前綴到底是標識char數組,還是標識一個std::string,還是一個CString?
匈牙利命名法的前綴如果太短,無法准確表達類型定義,如果太長又容易讓人困惑。匈牙利命名法在被用作代表多個屬性的時候會造成困惑,一個長的離奇的例子是:如 a_crszkvc30LastNameCol:一個常量引用參數,保存了一個varchar(30)類型的數據庫列LastName的內容,而這列又是這個表的主鍵的一部分。你對前面的那段縮寫會有任何感覺嗎?
而且現在的C++的代碼,名稱都在向更長的方向發展(無論是名稱還是名字空間),縮寫在這方面表現也會痛苦。
匈牙利命名法並不幫助編譯器進行類型檢查也不加快開發速度
匈牙利命名法在編譯器做類型檢查時是多余的。特別是對於C++這樣的強類型語言,一個提供類型檢查的語言在確定一個變量與其類型一致時,比人眼僅僅檢查變量的用法與變量名一致要強大的多。
一些現代的集成開發環境,如Visual Studio(source insight),特別是安裝了Visual Assist后。在需要時都可以顯示變量類型,並且自動標記不匹配的類型。使用這種命名法完全沒有必要。
大多數時候,看到一個變量就意味着知道了它的類型。但是,如果你不知道一個變量是干什么的,知道了它的類型也沒什么幫助。
保持前綴不利於重構
在代碼更改后可能造成不一致。如果一個變量的類型改變了,不是變量名的修飾與新的類型不一致,就是變量名必須被改變。由於變量名和類型捆綁在一起,因此不利於代碼的移植。一個典型的眾所周之的例子就是WPARAM類型,以及在許多Windows系統函數聲明中使用的wParam參數。它原本是一個16位的類型(w其實是WORD),但是在后來的操作系統中被改成了32位或64位,但仍保留原來的名字(它實際的基礎類型是UINT_PTR,即一個大小足夠保存一個指針的無符號整型)。
C++經典對話系列對匈牙利命名法的評論
"避免使用匈牙利記法,它會讓你的承諾落空。 贅物並非信息,而是混淆耳目的偽信息。"
而這篇文章是如此之長,而這個系列是如此之好,所以我建議大家自己閱讀這個系列,
微軟已經不再建議大家使用匈牙利命名法
正是出於上面的這些原因,早期堅定擁護匈牙利命名法的Microsoft在.NET Framework后,已經不再建議程序員使用匈牙利命名法了。
微軟新的變量名稱建議 General Naming Conventions原文如下:
Do not use Hungarian notation. Hungarian notation is the practice of including a prefix in identifiers to encode some metadata about the parameter, such as the data type of the identifier.
既然微軟都已經拋棄了這種方法,大家還留戀干嘛。
那么采用什么樣的命名規則更好?
前面講述了匈牙利命名法的類型縮寫前綴是應該去掉的理由。但實際談到命名的時候,爭論還是很多。微軟新的變量名稱建議仍然不推薦使用下划線,而UNIX大部分的規范寫法卻是使用全部小寫,加下划線的,個人的感覺如果是為了表示單詞的分割,下划線寫法和駝峰的寫法沒有太具體的差別。
那么可以對於習慣於現有匈牙利命名法的團隊,保留m_的表示成員變量,其他字符用於描述變量含義,不加前綴的方式可能改動成本更低,大家更容易接收。
而且后台開發團隊,向GNU代碼風格靠攏,采用小寫單詞+下划線結合,可能是更好的選擇。
當然代碼規范是一個團隊的事情,我這兒給出的只是一些建議,具體仍然要看團隊要求。
附錄:參考文檔
本文檔是下面這些文檔的整理版,版權歸他們所有。
《The Hungarian Revolution》Simonyi and Heller 1991,對不起,我沒有搜索到鏈接。
《匈牙利命名法》:維基,最好的百科全書
《這才是真正的"匈牙利命名法"》 :xuxn 作者是在閱讀《More Joel on Software》(中文名稱《軟件隨想錄》)后總結的博文。
《More Joel on Software》Joel Spolsky 中文版 《軟件隨想錄》阮一峰 :其中的23章探討過大家錯誤應用匈牙利命名法的問題。
《C++經典對話》Herb Sutter 和 Jim Hyslop,中文翻譯是徐波等人,這是一些關於C++很有意思的對話,其中第17章是討論匈牙利命名法的,遺憾的是中文版本幾乎沒有鏈接,網上有的都是chm文件的下載。
《Code Complete》 Steve McConnell 中文版本《代碼大全》金戈 / 湯凌 / 陳碩 / 張菲 譯 / 裘宗燕 審校:代碼大全是微軟的一套關於代碼編寫最全面的叢書,中間的11章討論的代碼命名規范問題,文中說的標准前綴一節的命名思路比較接近查爾斯·西蒙尼的論文原意。
【本文作者是雁渡寒潭,本着自由的精神,你可以在無盈利的情況完整轉載此文檔,轉載時請附上BLOG鏈接:http://www.cnblogs.com/fullsail/ 或者http://blog.csdn.net/fullsail,否則每字一元,每圖一百不講價。對Baidu文庫加價一倍】