This document is part of the HTML publication "An Introduction to the Imperative Part of C++"

The original version was produced by Rob Miller at Imperial College London, September 1996.

Version 1.1 (modified by David Clark at Imperial College London, September 1997)

Version 1.2 (modified by Bob White at Imperial College London, September 1998)

Version 1.3, 1.4, 2.0, ..., 2.21, 3.0 (modified by William Knottenbelt at Imperial College London, September 1999-September 2023)


Appendix 2: Debugging

A.2.1 General Tips on Debugging

The "assert" Function

A useful debugging procedure is to put the include directive

	#include <cassert>

at the top of your program (old-style header assert.h), and add various statements of the form

	assert(logical-expression);

at key points within it, to check that certain conditions which you think should be true (at those points) do indeed hold. If the program executes the above statement and the expression "logical-expression" is false, the program will terminate at that point with an appropriate error message. "assert" statements can be especially useful to check maximum/minimum value conditions, e.g.:

	...	
	assert(my_var >= 0 && my_var <= MAXIMUM_VALUE);
	...

or check for the success of file operations:

	...	
	assert(!in_stream.fail());
	...

You can "turn off" and "turn on" the assert checking by respectively adding and deleting (or commenting out) the line "#define NDEBUG", before the line "#include <cassert>". (See Savitch, Section 5.5, for further information about the "cassert" library.)

(BACK TO COURSE CONTENTS)

Stubs and Drivers

It is good practice to test each function you write with a separate short "driver" program before using it in other longer or more complex programs. The driver program might typically be a simple "while" loop that allows you to pass various parameters to the function from the keyboard, until you are satisfied that the function works properly.

If you are unsure about the overall control flow of your main program, it is often convenient to first test it with "stub" functions, which merely return an arbitrary value of the correct data type. This technique is especially useful when using a top down design method, and facilitates procedural or functional abstraction.

(BACK TO COURSE CONTENTS)

Some Common Errors to Look Out For

Debugging Very Bad Programs

If your program is very bad, the best way to debug it is to throw it away and start again.

(BACK TO COURSE CONTENTS)

A.2.2 The GNU debugger gdb

The gdb debugger is a powerful tool for tracking down errors in your programs. You can run gdb from the UNIX prompt by typing gdb program or you can run gdb from inside emacs by typing ESC-x gdb (this has the advantage that emacs will indicate the current program line by placing an arrow '=>' in the left hand margin of the corresponding source file). To include debugging information remember to compile your program with the -g option.

Below is a summary of the most useful commands. For a full description of all available commands type info gdb at the UNIX prompt; alternatively consult the official gdb manual page or try a good gdb tutorial.

r            run program until breakpoint, natural termination or fatal error
c            continue/resume program execution
s            step until next line (will step into function calls)
n            continue until next line (steps over function calls)
finish       continue until function in current stack frame returns
break        set breakpoint (argument can be function or line number)
watch        set watchpoint (argument is an expression; debugger will
               stop execution whenever expression changes)
info break   list all breakpoints and watchpoints
where        show stack trace
up           move to higher stack frame
down         move to lower stack frame
print        displays the values of a variable in the current stack frame
quit         quits the debugger

(BACK TO COURSE CONTENTS)