Coding Standards for D.A.M.E.

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.

Structure of a Hungarian Name

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."));

On Creating New Tags

When creating a new tag for a type, use the following guidelines:

Tags and Prefixes Used

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++.

Prefixes

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

Primitive Types

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.

Win32 Types

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

COM and MAPI Types

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

Application Types

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)

Different Hungarian Dialects

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.

Additional (Non-naming) Style Notes

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.


Other destinations

Book
Go to the main page for this book
Ben Goetter
Go to the author's personal home page
Site Map
Find your way around this site

Last modified: 13 August 1998

Ben Goetter (contact information)

Copyright 1996-1998 Ben Goetter. All rights reserved.