匈牙利命名法

**匈牙利命名法**（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"）但是沒有指明這個字串是如何實現的。

西蒙尼建議的大多數字首都是自然語意的，但不是所有。下面幾個是來自原始論文的：

* `p**X**` 是指向另一個 **X** 類型的指標，這包含非常少的語意資訊。
* `**d**` 是一個字首表示兩個值的區別，例如，**dY** 可能代表一個圖形沿 Y 軸的距離，而一個僅僅叫做 **y** 的變數可能是一個絕對坐標。這完全是自然語意的。
* `**sz**` 是一個無結束或零結束的字串。在 C 中，這包含一些語意資訊，因為 C 語言的_**char\***_類型的變數不確定是一個指向單個字元的指標，還是一個字元陣列，或是一個零結束字串。
* `**w**` 標記一個變數是一個字。這基本上沒有包含什麼語意資訊，因此可以被看作一種系統匈牙利命名法。
* `**b**` 標記了一個位元組，和 w 對比可能有一些語意資訊，因為 C 語言中，只有 **char** 型（以及 signed/unsigned char) 是一個位元組長的，這些類型有時候被用來儲存數值而字元。這個字首可以明確某個變數儲存的是字元還是數值。

由於這種命名法通常使用小寫字母開頭用來助記，但是並沒有對輔助記憶碼本身作規定。有幾種被廣泛使用的習慣（見下面的範例），但是任意字母組合都可以被使用，只要它們在代碼主體中保持一致就可以了。

在使用匈牙利應用命名法的代碼中有時候也可能包含系統匈牙利命名法，即在描述被單獨以類型方式定義的變數時使用。

## 範例

每一項範例的代碼塊表示實際生產環境代碼中可能出現的命名，範例後的兩項解釋分別為含義以及這一範例的字首是哪一個英文單詞的簡寫

* `bBusy`：布林型 bool
* `cApples`：專案計數 count
* `dwLightYears`：雙字（系統） doubleword
* `fBusy`：布林型或浮點型 false&true 或 float
* `nSize`：整型（系統）或計數（應用）nature
* `iSize`：整型（系統）或索引（應用）int
* `fpPrice`：浮點數 floatpoint
* `dbPi`：雙精度浮點數（系統） double
* `pFoo`：指標 point
* `rgStudents`：陣列或範圍 range
* `szLastName`：零結束字串 ß
* `u32Identifier`：無符號 32 位元整型（系統） unsigned32
* `stTime`：時鐘結構 struct
* `fnFunction`：函式名 function

對於指標和陣列來說，它們實際上並不是資料類型，因此通常在輔助記憶碼後面跟著實際元素的類型。

* `pszOwner`：指向零結束字串的指標
* `rgfpBalances`：浮點值的陣列

儘管匈牙利命名法可以被應用在任何程式設計語言和環境中，由於微軟在 C 語言專案中，特別是在 Microsoft Windows 里的大量應用，使得匈牙利命名法的應用大量存在於和 Windows 相關的領域：

* `hwndFoo`：窗口控制代碼 handle window
* `lpszBar`：指向零結束字串的長指標 longpointß

這種命名法又是在 C++ 中被擴充而包含變數的作用域，由一個底線隔開：

* `g_nWheels`：全域命名空間的成員，整型
* `m_nWheels`：結構體／類別成員，整型

## 匈牙利命名法的優點

（其中一些只適用於系統匈牙利命名法）
支持者聲稱匈牙利命名法的好處包括：

* 不需要整合式開發環境的支援，從名字中就可以看出變數的類型
* 擁有類似語意的多個變數可以在一個代碼塊中使用：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)