How we change what others think, feel, believe and do
CHAPTER 6 : Layout
6.15 Data declarations
Data is often one of the less clear elements of a program and taking time to keep the layout clear is particularly worthwhile.
6.15.1 Ordering specifiers
A declaration consists of a combination of type qualifier (const, volatile) storage class specifier (auto, register, extern or static) and type specifiers (unsigned, signed, char, short, int, long, float, double, structs, union's, enum's, typedef's). The order in which they are used may vary:
int long unsigned extern AuthorName /* this way? */
The clearest, most portable and most common way is to start with storage class specifiers, follow with type qualifiers (if any) and then type specifiers. Within type specifiers, saying int long is equivalent to saying 'man tall'. It is proper English to put the adjectives before the noun: 'tall man'. The C equivalent is long int. It is also common to put signed or unsigned first. Thus:
extern unsigned long int AuthorName /* this way!! */
6.15.2 One declaration per line
Variables of the same type can be declared on the same line, although this can cause readability problems:
Here, i has a physical, but not logical, association with FirstPrime; it is also difficult to find. Also, the variables cannot be commented separately. Putting only closely associated variables in the same statement, but on separate lines, solves many, but not all problems:
This can still cause editing problems, and if a page break occurs between the two lines, SecondPrime is left dangling anonymously. This format can also cause problems with const and volatile. It is simpler and more explicit to declare each variable separately. Logical association is shown with vertical proximity:
Data declarations contain at least two distinct parts, the type and the identifier. The reader of a program will typically scan lists of data declarations when looking for a known variable name. Vertically aligning identifiers helps this process (as well as making it tidier in appearance):
Strict adherence to this means that the name always starts in the same column. If the column position is already passed, then the name will start in the standard column, but on the next line:
This may be relaxed to allow variable alignment columns, where items need vertically align only in the current 'chunk'. This 'toothbrush' approach however may cause space problems on the line:
int DB_Status; /* Start of Chunk 1 */
The alternative is to allow ragged alignment, which is not as clear as vertically alignment:
6.15.4 Table layout
Data tables can be made more readable by vertically aligning declarations and initializers:
Note how braces are used to contain groups. Note also the comma on the last data line - this avoids problems when further lines are be added.
6.15.5 Pointer layout
In pointer declarations the asterisk is commonly put adjacent to the variable name, as this is how it will be used in statements. An alternative is to associate it in the declaration more closely with the type:
char *ScreenName; /* "*ScreenName is a char" */
char * ScreenName; /* "ScreenName points to a char" */
The second variation makes the pointer clearer (note how the '*' is surrounded with white space to make it stand out), it reads better, and is consistent with function prototype arguments and with the layout in 6.?.?. It is, however, less common than the first layout and can be confusing if multiple variables are declared on one line.
6.15.6 Structure tags
A structure may be declared for future use at the same time the structure is defined:
This is using the declaration for two purposes. It is more explicit and consistent to separate the definition and declaration:
6.15.7 Limited-value variables
Where a variable can only have a limited range of values, these should be declared as close as possible to the variable declaration:
Note that declaring items with tags or typedef's enables the declaration and its constants to be placed together in a single header file.
And the big