Global variables are highly undesirable. Even static variables within
a file are undesirable, especially when used to avoid passing parameters.
With as few exceptions as possible, all variables accessed by a function
should be parameters to it or locals. This allows people reading the
code to be able to understand a function without looking outside the
function code itself.
Also it allows a function to be relocated to another file without relying
on static variables within the original file.
An example of a valid use of global variables would be as run-time constants, i.e., values which might be initialized at the beginning of the program, and then accessed in a read-only manner.
Continuation lines of functions should line up with the '(', if
reasonable:
x = find_shortest_path( p1, p2, p3, parameter4, parameter5 );Exception: (if no room)
{ x = find_shortest_path( parameter1, parameter2, parameter3, parameter4, parameter5, parameter6 ); }
In most cases, you should use a defined constant instead of a numerical
constant, as a documentation aid:
WRONG:
index = day / 7;RIGHT:
index = day / NUMBER_DAYS_IN_WEEK;
Exceptions to this rule occur where it is clearer and easier to maintain correctness by using an explicit numerical constant:
avg = (p1 + p2 + p3 + p4) / 4;
while( function() );because someone might someday add code for the body of the loop, and forget to take out the semicolon:
while( function() ); { body(); }The above is valid C code, but does not do what is required. Use:
while( function() ) { }
For structures that are 8 bytes or more, it is much more efficient to
pass by reference, rather than value, for most compilers.
public void function( parameter ) image_struct *parameter; { }
Full-line comments should be at the same
indentation level as the
code, with a blank line above and below.
Same-line comments should be
separated from the code by many spaces:
n = 10; /* find the largest value in the array */ max = a[0]; for( i = 1; i < n; ++i ) { if( a[i] > max ) { max = a[i]; /* new max */ } } c = max; /* initialize counter */
Use enumerated types for variables with a limited number of values.
WRONG:
#define MR_FORMAT 1 #define PET_FORMAT 2 #define IFF_FORMAT 3 #define FREE_FORMAT 4 main() { int input_format; input_format = MR_FORMAT; }RIGHT:
typedef enum { MR_FORMAT, PET_FORMAT, IFF_FORMAT, FREE_FORMAT } file_format_types; main() { file_format_types input_format; input_format = MR_FORMAT; }
Use explicit type-casting whenever conversion between types is to
be done:
{ int int_x; float float_x; float_x = 3.56; int_x = (int) float_x; } { voxel_struct *current_voxel; if( current_voxel == (voxel_struct *) 0 ) { exit( 1 ); } }
Never treat integers like booleans (flags). Never treat booleans like
integers:
WRONG:
{ int invert_flag; int number_of_slices; if( number_of_slices ) { } if( invert_flag == 0 ) { } }RIGHT
{ int invert_flag; int number_of_slices; if( number_of_slices != 0 ) { } if( !invert_flag ) { } }
One possible exception is:
/* returns 0 or an error */ if( input_file( file, data ) ) { (void) print( "Error\n" ); }