The names that are used for constants, variables, functions, etc. are critically
important to good maintainable code. Names should always be descriptive. Avoid using terse
and non-obvious names. Conversely don't be overly verbose with your names. Public names
are the most critical since other programmers are likely to use them.
| Use descriptive names
|
Make identifier names descriptive of their contents.
Avoid terse names that have little or no meaning. |
| Limit names to 32
characters |
Generally names and identifiers should be less than 33
characters long. They must be unique within 31 characters. |
| Avoid names that differ only
in case |
Names that differ only by case should be strictly
avoided. This especially true of public/global names. |
| Avoid names that look like
each other |
Names that are ambiguous to the human reader should be
strictly avoided. For instance: "l" (lower-case L) and "1" (numeric
digit one) can be easily confused or "O" (upper-case letter O) and "0"
(numeric digit zero). Similarly, avoid differences like "foobar" and
"foo_bar", the potential for confusion is considerable. |
| Begin typedef names
with a capital letter |
The typedef name should always begin with a capital
letter. Typically, if a typedef's name includes more than one word, each word is
capitalized and concatenated.
typedef struct StringCounted StringCounted;
|
|
| Use the same name for the
structure tag and the typedef name |
If a structure tag name is used it should be identical
to the typedef name. Another consideration is that the typedef name should be such that
collision with a typedef that is in a system include file on any of the (many) systems we
support is unlikely. For this reason, avoid a typedef name like Rect. A better name
would be DeptRectangle ("Dept" indicating a department abbreviation) or
something else that is unlikely to collide. There are some cases where this guideline has
not been followed in the past, and eventually it is going to cause us problems. Let's make
sure we do not create any more.
typedef struct Point2d
{
long x;
long y;
} Point2d;
|
|
| Avoid underscores in typedef
names |
Underscore characters should be strictly avoided when
creating new typedef names. |
| Begin variable and
parameter names with a lowercase letter |
There are two forms of variables in 'C', local (or
private) and global (or public). Both should always begin with a lowercase letter.
Each subsequent "word" in the name should be capitalized and concatenated to the
previous word. It is important to use variable names that have clear and non-ambiguous
meanings. In general functions should be kept relatively small, so the need for long
descriptive local variable names is limited. The important consideration is that all
functions within a file should have consistency between them. |
| Simplified Hungarian notation
for variable names |
Some Companies, most notably Microsoft, have
standardized on the Hungarian Notation. In Hungarian Notation, variables are to be
prefixed with lowercase tags followed by the variable name "words" each
beginning with a capital letter. An example:
Which indicates pointer to double. In most cases there will be a single or double
character prefix. The complete Hungarian Notation is highly complex, however the following
is a simplified form of the prefixes and their corresponding meanings.
| Characters |
| c |
char |
| s |
string (char* or char []) |
| sz |
string - zero terminated (synonym for 's') |
| sc |
string - counted (first byte contains character count) |
| sw |
wide-character string |
| Integers |
| i |
int |
| n |
int or long-int |
| u |
unsigned |
| w |
word (unsigned short) |
| Floating point |
| f |
float |
| d |
double |
| r |
real (probably double) |
| Enumerations |
| e |
enum |
| Boolean (true or false) |
| b |
boolean (true or false) |
| Structures (typedef) |
| t |
tag (typedef or struct) |
| Other general prefixes |
| a |
array |
| p |
pointer |
| h |
handle (pointer to pointer) |
| k |
constant |
| g |
global variable |
|
| Prefix global variable
names with "g" |
It is important that public variables be descriptive
enough that collision with variables or functions in the name space of one of the (many)
systems our products run on do not occur. For example a public variable called 'error' is
a poor idea, since it is almost sure to conflict on some system. A possible solution is to
precede the name with an indication that it is global, for example a lower case 'g'. There
are several special considerations that need to be observed when dealing with variables
that have public scope. Please remember that non-static variables defined outside of a
function are public names. |
| Don't count on capitalization
to differentiate names |
Don't count on case sensitivity to make ANY public
names (functions or global variables) unique. Some systems or development environments
convert all public names to a single case for the link process. |
| Limit the number of global
variables |
Some machines or linkers have a limited number of
global variables. If you must use global variables, cluster the variables into logical
structures and then define the structures global. |
Public declarations should be kept to the absolute minimum required. If the function is
only referenced from within the source file, define it as static. When creating a
new function, the natural tendency should be to make it static. Since the scope for
static functions and variables is limited to the source file that defined them, if one is
changed, it is not necessary to search outside of the current source file to resolve
references.
Even if code is destined for only one machine, the data sizes should not be assumed.
| The 'int'
data type should be treated as a 'short' data type |
int is defined to be the natural size of an
integer on the hardware. Since an int on some systems is the size of a short an
int should always be assumed to be no larger than a short. Another way to
think about it is that an int should never hold more data than a short but
may occupy the memory of a long. |
| Never assume the sizes of
data types |
You should never depend on the size of types int,
double or pointers. Some programmers assume that an int and a long and a pointer are all
the same size. Or that a double is always going to be 8 bytes. These are bad and dangerous
assumptions, especially as they relate to structures.
| type |
80x86 |
680x0 |
Clipper |
Cray-2 |
Unisys 1100 |
| char |
8 |
8 |
8 |
8 |
9 |
| short |
16 |
16 |
16 |
64(32) |
18 |
| int |
16/32 |
16/32 |
32 |
64(32) |
36 |
| long |
32 |
32 |
32 |
64 |
36 |
| char* |
16/32/48 |
32 |
32 |
64 |
72 |
| int* |
16/32/48 |
32 |
32 |
64(24) |
72 |
| int (*)() |
16/32/48 |
32 |
32 |
64 |
72 |
|
| Use typedefs to create
predictable data sizes |
If a predictable datum size is needed then a typedef
should be declared and used for definitions. This will allow the typedef to be
conditionally declared based on machine/system sizes. |
| Be careful about the range
and precision for floating point |
It is dangerous to assume that when a floating point
value allocates a given number of bits that the range or precision are always completely
allocated. |
| Avoid assumptions concerning
memory alignment |
Some machines require data types to be aligned in
memory based on their elemental sizes. This can cause unused holes in memory. This is
especially obvious when dealing with heterogeneous structures. |
| Avoid assumptions concerning
memory order |
Some machines organize memory such that bytes of a word
are of increasing significance with increasing address (little-endian), or of decreasing
significance with increasing address (big-endian). |