匈牙利命名法的辩思
随手打开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文库加价一倍】