The sample applications in D.A.M.E. adhere to a set of standard conventions for variable naming. The style of the naming scheme is called Hungarian, both for the nationality of its inventor Dr. Charles Simonyi and for the throat-rattling aggragates of consonants that constitute names following this scheme.
The basic idea behind Hungarian is that a variable name recapitulates its type. A code writer names variables without thought, by their type and usage. A code reader immediately sees the type, and from that can often tell whether an operation on a variable is correct, simplifying verification and code review. By agreeing on a standard, multiple authors can cooperate easily on a single project.
Like Gaul, a Hungarian variable name is divided into three parts: prefix, tag, and qualifier.
The tag is the heart of the name, describing the underlying type of the variable. This type can be a native type of the underlying computer language, such as char or unsigned long in C; a defined type, such as is created with the typedef, struct, or class declarations in C and C++; or a logical type, such as an integer used as part of a Cartesian coordinate, or a simple number. Common tags include b for byte, ch for character, sz for NUL-terminated string of characters, and n for a simple number.
unsigned char b;
TCHAR ch;
static TCHAR sz[] = __T("Z");
int n;
A prefix may precede the tag. The prefix states that the variable is not of the type used in the tag, but instead is of a type associated with the tag's type, such as a count of elements of that type, a pointer to a single instance of that type, or a contiguous array of instances of that type. Common prefixes include c for counter, p for pointer, rg for contiguous array, and i for index into an array. For example, pch denotes a pointer to a character, while cb denotes a count of bytes. Prefixes may be compounded: thus pp denotes a pointer to a pointer, or double indirection, as is seen with ppsz, a pointer to a pointer to a NUL-terminated character string.
static TCHAR sz[] =
__T("Z");
TCHAR* pch = &sz[0];
int cb = sizeof(sz);
TCHAR* psz = sz;
TCHAR** ppsz = &psz;
Note the special relationship between sz and psz. This is a side-effect of the C-language automatic translation between named arrays and pointers to the first elements of arrays. A sz is nothing more than a rgch that contains NUL-terminated data. A psz is a pch that points to such a sequence.
An optional qualifier may follow the tag. This can supply more information about the usage of the variable, or may simply differentiate the variable from other variables of the same type. A project will usually have a few standard qualifiers, such as Tmp for temporaries or Max for a maximum limit. Hence cchMax names the maximum count of characters, pszTmp names a temporary pointer to a string, and rgchBuffer names an array of characters more descriptively.
TCHAR rgchBuffer[256];
int cchMax = sizeof(rgchBuffer)/sizeof(TCHAR);
TCHAR* pszTmp = _tcsdup(__T("Your
mother."));
When creating a new tag for a type, use the following guidelines:
Any project adhering to Hungarian discipline must maintain a consistent set of standard tags and prefixes used within the project. Ideally, the project will maintain a formal dictionary of these. Here are the tags and prefixes that I used in the code samples for Developing Applications for Microsoft Exchange with C++.
Except for the sp prefix, these are standard to all Hungarian projects.
Sometimes sloppy code will use a prefix in the place of a tag. For example, a reference counter may take the name _cRefs, indicating that it is a count - but of what, it does not specify. Pointers also often use this idiom, particularly when the type of the object referenced does not yet have a Hungarian tag defined: hence ppPersist, a pointer to a pointer to an unspecified object (here, an interface of IPersistMessage). Note that a truly untyped pointer uses the v tag, e.g. pvContext for pointer to void.
| Prefix | Meaning |
|---|---|
| c | Count of elements |
| i | Index into sequence of elements |
| d | Difference between indices or elements |
| rg | Array of elements |
| p | Pointer to element |
| h | Handle to an element (see Win32 Types) |
| sp | "Safe" pointer to component object interface, using the templates from safeiptr.h |
These are standard to all Hungarian projects.
| Tag | Underlying Type | Meaning |
|---|---|---|
| b | BYTE |
(typedef for unsigned char from windows.h) machine byte |
| w | WORD |
(typedef for unsigned short from windows.h on x86) machine word |
| dw | DWORD |
(typedef for unsigned long from windows.h on x86) machine double word |
| ch | TCHAR |
A character: either unsigned char or unsigned short, depending on the value of the _UNICODE manifest |
| n | Any integer type | A number |
| sz | TCHAR[],or char[] |
NUL-terminated character string |
| f | BOOL |
(typedef for int from windows.h)
Boolean logical value, taking the value TRUE
or FALSE. Mnemonic: the f stands
for flag. |
| fn | function address | Address of a callable function. Usually seen with one or more pointer prefixes, e.g. pfn. |
| v | Void type | An unknown, unspecified type. Usually seen with one or more pointer prefixes, e.g. pv. |
| x | Any integer type | Cartesian X coordinate |
| y | Any integer type | Cartesian Y coordinate |
| ul | unsigned long |
Explicit C-type tag, used only when no logical type available. Dependence on such explicit C type tags is poor Hungarian usage. |
| us | unsigned short |
Explicit C-type tag, used only when no logical type available. Dependence on such explicit C type tags is poor Hungarian usage. |
These are standard to Hungarian projects written to Win32. Most encode types from the standard windows.h header file.
| Tag | Underlying Type | Meaning |
|---|---|---|
| xy | POINT,or POINTL |
Cartesian coordinate pair |
| rc | RECT,or RECTL |
Rectangle |
| id | int |
Resource identifier |
| ids | int |
ID of a string resource |
| idd | int |
ID of a dialog resource |
| idc | int |
ID of a control within a dialog |
| h | HANDLE |
Generic handle from the OS. Also used much like a prefix, as in the following examples |
| hkey | HKEY |
Handle to a registry key |
| hwnd | HWND |
Handle to a window |
| hdlg | HWND |
Handle to a dialog |
| hdc | HDC |
Handle to a device context (DC) |
| hbr | HBRUSH |
Handle to a GDI brush |
Some of these follow standard usage as they appear in Microsoft source code samples, while others I coined for the Widgets project, or for this book.
This list is incomplete.
| Tag | Underlying Type | Meaning |
|---|---|---|
| hr | HRESULT |
Standard API return code |
| unk | IUnknown |
Unknown component object |
| fact | IClassFactory |
Class factory object |
| tbl | IMAPITable |
MAPI generic table object |
| sess | IMAPISession |
MAPI session object |
| mdb | IMsgStore |
MAPI message store object |
| stat | IMAPIStatus |
MAPI status table support object |
| sink | IMAPIAdviseSink,IMAPIViewAdviseSink,or IMAPIFormAdviseSink |
MAPI advise sink object |
| vwctx | IMAPIViewContext |
MAPI view context object |
| prof | IProfSect |
MAPI profile section object |
| rs | SRowSet |
MAPI row set structure |
| taga | SPropTagArray |
MAPI property tag array structure |
| val | SPropValue |
MAPI property value structure |
| err | MAPIERROR |
MAPI extended error information return structure |
| bin | SBinary |
MAPI binary value structure |
When a project defines a new type, it should at the same time define the Hungarian tag for that type. Here are a couple of the most common application-specific objects appearing in the book's source code samples.
| Tag | Underlying Type | Meaning |
|---|---|---|
| ui | CUICommon,or any derived class |
Application UI object (see ui.cpp and ui.h) |
| cmdline | CCmdLine |
Application command-line parsing object (see cmdline.cpp and cmdline.h) |
Other dialects of Hungarian exist.
One common dialect appears in the Microsoft Windows SDK header files. It betrays its segmented-architecture origins with special near-pointer and far-pointer prefixes, respectively np and lp.
Another dialect uses the prefix a for array, the tag b for Boolean, and depends extensively on C type tags such as us, ul, s, and l.
I use neither of these.
Class definitions prefix the names of their private and protected member variables with a single underscore. Hence in the implementation of a member function, the sequence
if (EECONTEXT_VIEWER == _context)
...
denotes that the conditional references the state of a member variable.
Any function taking a class reference as a parameter must
declare that reference as const. Functions with side
effects on their parameters must accept explicit pointers to
those parameters, not C++ references to those parameters.
Last modified: 13 August 1998
Copyright 1996-1998 Ben Goetter. All rights reserved.