Programs, books, and techniques for debugging C or C++ programs.

From: Richard Heathfield (dontmail_at_address.co.uk.invalid)
Date: 11/14/03


Date: Fri, 14 Nov 2003 04:58:13 +0000 (UTC)


[It is normal practice to quote all the relevant bits of the article to
which you are replying. I have complied with that normal practice as usual
but, as you can see...]

The change of subject line to "Debugging programs and books: The life of a
programmer." is ambiguous. I read it as if "debugging" were an adjective
rather than a verb, which led me to expect an article on the kinds of books
and programs a programmer might commonly expect to use during the course of
his career. Perhaps a request for recommendations, or something like that.

Such a discussion would not be topical in this newsgroup (although it would
be right up comp.programming's street), unless it had some particular
relevance to C, or to C++, or both.

So it is my intention to broaden the thread slightly (whilst remaining as
much on-topic as I can!). Hence another rewording of the subject line to:
"Programs, books, and techniques for debugging C or C++ programs."

It is /not/ my intention, however, to provide an exhaustive list! But maybe,
between us, we can at least provide an exhaust/ed/ list, which might prove
to be of some use to neophyte programmers.

So let me start the ball rolling with two programs, two books, and two
techniques.

Programs

The most obvious program to start with is gdb. It is highly likely that a
version of gdb is available for the platforms used by all, or at least
/almost/ all, the people using this newsgroup. Learning how to use a good
debugger is an essential skill.

My second debugging program suggestion is not quite so well-known: a hex
dump utility. If you don't have one, don't worry; they are quite easy to
write in standard ISO C or C++, and writing your own makes for a mildly
diverting 5 to 10 minutes. (I said "dump", not "edit"!) I use hex dumpers
mainly for checking that I have indeed written files in the format that I
expected and intended them to be written.

Books

"Writing Solid Code", by Steve Maguire, expounds the theory that prevention
is better than cure, and tries to show you ways to write /better/ code,
code that is less likely to have bugs in it. Unfortunately, the tips Mr
Maguire shows are not always portable (he is (or at least was) a Microsoft
programmer), but the /attitude/ is definitely portable. Focuses mainly on
C.

"Code Complete", by Steve McConnell, is a much more broadly-based book, but
it includes a 30-page chapter on debugging. Not particularly focused on C
or C++; rather, the advice is language-independent. Nevertheless, it is an
excellent book, and not just because of this chapter.

Techniques

Okay, the first technique I'm going to suggest is the assert() macro. These
are very handy for finding program errors (but rarely, if ever, useful for
finding data validation errors, because a data validation error ought to be
recoverable, whereas an assertion failure most definitely is *not*). Do you
know for sure that your code is so well-written that /this/ function can
*never* get a null pointer passed to it? Good! So prove it.

  assert(p != NULL);

I just did grep assert *c | wc -l on my current development project and
found that I currently have 57 assertions in place. Most of them are checks
against NULL, as above, but a few (all right, 23) call a string validation
routine; here, I am asserting that the function in question will only ever
be passed a valid "string" (not really a string, actually, but never mind
that for now).

In another project I have on the go, my use of assert is slightly more
varied. I have, as well as many checks against NULL, one or more instance
of each of the following assertions:

assert(len > 0);
assert(Base >= 2 && Base <= 36);
assert((int)A->n[i] + (int)B->n[i] + (int)MF_MSB(Total) <= USHRT_MAX);
assert((int)A->n[i] + (int)MF_MSB(Total) < USHRT_MAX);
assert(0 == Carry);
assert(0);

The last one has a certain panache. It's a sort of runtime equivalent of a
"can't reach here" comment. :-)

I promised you two techniques. Here's the second. In a structure, surround
your data with tags that have a constant value - either a very common
value, such as 0, or (perhaps more usefully) a constant value which applies
only to that structure. You can test for these tags. If they later change,
you know that the fields in the struct have been corrupted somehow. Since
you probably only want to do this during the debugging stage, you can
combine this with assertions to great effect.

My example has been pinched from a book which will remain nameless. It uses
0 as its constant. (This is probably not a great choice, but it'll do.)
Here's an extract from the header:

typedef struct DEQUE
{
#ifndef NDEBUG
  int CheckInit1;
#endif

  DLLIST *HeadPtr;
  DLLIST *TailPtr;
  size_t NumItems;

#ifndef NDEBUG
  int CheckInit2;
#endif
} DEQUE;

And here's an extract from the code:

int DequeAddAtFront(DEQUE *Deque,
                    int Tag,
                    void *Object,
                    size_t Size)
{
  int Result = DEQUE_ADD_FAILURE;
  int ListResult;
  assert(Deque != NULL);
  assert(0 == Deque->CheckInit1 && 0 == Deque->CheckInit2);

So the program fails if the memory gets corrupted.

Anyone care to add to this list?

-- 
Richard Heathfield : binary@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton


Relevant Pages

  • Re: [RFC PATCH 25/26] UBIFS: add debugging stuff
    ... Many kernel subsystems have their debugging, ... which are compiled-out by default, ... Why would you want to have assertions that are compiled out by default? ... lives of those crazy embedded folks that disable CONFIG_BUG for smaller kernel size harder as well. ...
    (Linux-Kernel)
  • Re: Lets _clear_ this up once and for all, shall we?
    ... To them, these books are erroneous, are lies. ... do not believe in these traditions. ... Please provide evidence for any of the assertions in that paragraph. ... very trustworthy in keeping the ancient Hebrew traditions accurate ...
    (talk.origins)
  • Re: Lets _clear_ this up once and for all, shall we?
    ... side) utterly refuse to believe that ancient tradition holds any ... To them, these books are erroneous, are lies. ... like evidence for any of the various assertions that you ... Kermit do not believe in these traditions. ...
    (talk.origins)
  • Re: OT: Screening MoFos
    ... debugging he quite blatantly told me that as he had never actually ... He'd never laid hands on a computer but ... some very good books as reference! ... his hands on a home computer and at least try running some of his ...
    (uk.rec.motorcycles)
  • Re: Force type for function?
    ... Assertions should be used as a debugging feature only. ... TRUE and that indicate some programming errors if not or to check for ... system limits and features. ... I mean, yes, they are for debugging, but at least for the projects I was working on, we were forever debugging. ...
    (comp.lang.php)