匈牙利命名法

匈牙利命名法（Hungarian notation）是电脑程序设计中的一种变数命名规则，此命名法又可细分为：系统匈牙利命名法和匈牙利应用命名法。

匈牙利命名法具备语言独立的特性，并且首次在BCPL语言中被大量使用。由于BCPL这种低级语言只有机器码这一种数据内容，因此这种语言本身无法帮助程序员来记住变数的类型。匈牙利命名法通过明确每个变数的资料型别来解决这个问题。

在匈牙利命名法中，一个变数名由一个或多个小写字母开始，这些字母有助于记忆变数的类型和用途，紧跟着的就是程序设计师选择的任何名称。这个后半部分的首字母可以大写，以区别前面的类型指示字母（参见驼峰式大小写）。

## 历史

原始的匈牙利命名法，现在被称为匈牙利应用命名法，由1972年至1981年在施乐帕洛阿尔托研究中心工作的-程序员查尔斯·西蒙尼发明。此人后来成了微软的总设计师。

这种命名法其实是对于西蒙尼祖籍的一种讽刺。匈牙利人名和大多数其他欧洲人名相比是反过来的，即姓氏在名字的前面。举个例子，英语化的名字“Charles Simonyi”在匈牙利语中原本是“Simonyi Károly”。同样的，在匈牙利命名法中，类型名在实际变量名前，而不是像大多数欧洲的Smalltalk那样，类型放在变量名后，例如aPoint和lastPoint。后者在西蒙尼任职于施乐帕洛阿尔托研究中心时期非常流行。这种命名法的灵感，可能是受波兰表示法的启发。

匈牙利命名法的英文是Hungarian notation，这个词能让许多人记住，因为难发音的辅音字串有点像部分东欧语言中，辅音丰富的拼写方式，尽管实际上匈牙利语是属于芬兰-乌戈尔语族，而不像斯拉夫语族那样元音丰富。举例来说，零结束字符串的前缀"sz"实际上就是匈牙利字母表中的一个合体字母（参看德语中的ß）。

## 系统匈牙利命名法与匈牙利应用命名法

系统命名法与应用命名法的区别在于前缀的目的。

在系统匈牙利命名法中，前缀代表了变量的实际数据类型。例如：

- `lAccountNum`：变量是一个长整数（"l"）;
- `arru8NumberList`：变量是一个无符号8位整型数组（"arru8"）;
- `szName`：变量是一个零结束字符串（"sz"），这是西蒙尼最开始建议的前缀之一。

匈牙利应用命名法不表示实际数据类型，而是给出了变量目的的提示，或者说它代表了什么。

- `rwPosition`：变量代表一个行（"rw"）。
- `usName`：变量代表一个非安全字符串（"us"），需要在使用前处理。
- `strName`：变量代表一个包含名字的字符串（"str"）但是没有指明这个字符串是如何实现的。

西蒙尼建议的大多数前缀都是自然语义的，但不是所有。下面几个是来自原始论文的：

```
   [[Microsoft]] Corp.，1999年11月，MSDN Library，''MSDN.microsoft.com''
   网页:[https://msdn2.microsoft.com/en-us/library/aa260976(VS.60).aspx 匈牙利命名法，查尔斯·西蒙尼，Microsoft Corporation] .</ref>
```

- 不需要集成开发环境的支持，从名字中就可以看出变量的类型
- 拥有类似语义的多个变量可以在一个代码块中使用：dwWidth，iWidth，fWidth，dWidth
- 变量名在仅仅知道他们的类型时可以被轻易记住
- 可以使变量名更加一致
- 决定一个变量名的时候可以更机械化，更快
- 不合适的类型转换和操作可以在阅读代码的时候被检测出来，而不需要编译器的检测
- 在那些数字被当作字符串处理的基于字符串的语言中非常有用（例如Tcl）
- 在匈牙利应用命名法中，变量名确保不会犯以下错误：

heightWindow = window.getWidth

- 在使用动态类型语言或完全无类型的语言编程时，关于类型的修饰可以更简化。这种语言一般不包含类型修饰（或者可选），因此唯一可以看出哪些类型是被允许的只有名字本身、文档以及通过阅读代码来明白它们在做什么。在这些语言中，包含对于变量类型的指示可能会有助于程序员。就像上面提到的，匈牙利命名法扩展了这样的语言（BCPL）。
- 在包含许多全局对象的复杂程序中（VB/Delphi Forms），拥有一个基本的前缀命名法可以简化在编辑器中查找组件的工作。按`btn<Ctrl-Space>`可以使编辑器弹出一个Button对象的列表。

## 匈牙利系统命名法的缺点

批评者认为：

- 匈牙利命名法在编译器做类型检查时是多余的。一个提供类型检查的语言在确定一个变量与其类型一致时，比人眼仅仅检查变量的用法与变量名一致要强大的多。
- 一些现代的集成开发环境，如Visual Studio在需要时可以显示变量类型，并且自动标记不匹配的类型。使用这种命名法完全没有必要。
- 向标识符添加类型标识导致标识符冗长；同时纵容相同主体名而不同类型的变量导致的歧义，开发人员无法从`sWidth`、`nWidth`、`fWidth`中了解这几个Width的用法区别，更好的写法可能是`string input`、`int width`、`float zoomedWidth`。
- 匈牙利命名法在被用作代表多个属性的时候会造成困惑，如 a_crszkvc30LastNameCol：一个常量引用参数，保存了一个varchar（30）类型的数据库列LastName的内容，而这列又是这个表的主键的一部分。
- 在代码更改后可能造成不一致。如果一个变量的类型改变了，不是变量名的修饰与新的类型不一致，就是变量名必须被改变。
- 由于变量名和类型捆绑在一起，因此不利于代码的移植。一个典型的众所周之的例子就是WPARAM类型，以及在许多Windows系统函数声明中使用的wParam参数。它原本是一个16位的类型，但是在后来的操作系统中被改成了32位或64位，但仍保留原来的名字（它实际的基础类型是UINT_PTR，即一个大小足够保存一个指针的无符号整型）。
- 大多数时候，看到一个变量就意味着知道了它的类型。但是，如果你不知道一个变量是干什么的，知道了它的类型也没什么帮助。

.NET Framework，微软新的软件开发平台，除了接口类型一般不适用匈牙利命名法。在.NET中，习惯在接口类型前放一个I（例如Windows Forms中的IButtonControl接口。）.NET Framework指导方针建议程序员不要用匈牙利命名法，但是没有指明不要用系统匈牙利命名法还是匈牙利应用命名法，或者是两者都不要用。但在JETBrains公司旗下C#编辑器中，匈牙利命名法却属于建议使用的命名法（.net使用C#语言开发）与此对比，Java的标准库中连接口类型也不加前缀。

## 内部连结

- 驼峰式大小写
- 蛇形命名法

## 外部链接

- Meta-Programming: A Software Production Method Charles Simonyi, December 1976 (PhD Thesis)
- https://blogs.msdn.microsoft.com/larryosterman/2004/06/22/hugarian-notation-its-my-turn-now/ – Larry Osterman's WebLog
- Hungarian Notation (MSDN)
- HTML version of Doug Klunder's paper
- RVBA Naming Conventions
- Coding Style Conventions (MSDN)