fprintf's
can be used to display information about
variables, function entries and exits, and function arguments and return
values. You should fflush()
the stream immediately afterward,
otherwise there is no guarantee that you will see the message if you program
crashes. This code should be surrounded by conditional compilation
directives to allow the debugging code to be stripped from the compilation
once the initial debugging process has been completed without removing all
the lines of code from your source. For example:
#define DEBUG_FUNCS
void thisfunc ( int f, char *e )
{
int g;
#ifdef DEBUG_FUNCS
fprintf ( stderr, "Entering `thisfunc'. f=%d, e=%s\n", f, e );
fflush ( stderr );
#endif
/* Body of function */
#ifdef DEBUG_FUNCS
fprintf ( stderr, "Leaving `thisfunc'. g=%d\n", g );
fflush ( stderr );
#endif
return ( g );
}
- Dumping variable values before and after branch points allows you to
see how the program is flowing and why. Logical errors such as incorrect
loop counts or conditions can be spotted using this information. Also,
loops whose conditional variables are not updated can also be found in
this manner.
- Announcing the beginning and end of a function can help you to narrow
down the search for an error to a particular function.
- Dumping functions arguments before and after calls allows you to see if
the arguments are being correctly transferred to the called function.
This sometimes happens if argument types do not match the type expected by
the function.
- Dumping functions return values before and after the return allows you
to see if the return value is what you expect. Sometimes functions are
not well-defined and return values that your higher-level routines do not
properly handle. This will help you to catch such problems.