printf() -- the ultimate debugger

When everything else fails, you're left with printf(). Maybe your program takes 3 hours to get to its failure point when optimised, and will never get there if you compile with symbolic information. Or maybe doing that moves data around, and a memory overflow that was crashing your program no longer does, so the debugger doesn't help.

Whatever the reason, you need printf(). Just remember to call it fprintf(stderr,...), so your log isn't on a buffered stream.

Lets see...
hello world test:
#include <stdio.h>
main() { printf("hello world\n"); }
vs
#include <iostream.h>
main() { cout << "Hello World\n"; }
And the results are:
  1. Size
    • printf size: 11735 (unstriped), 3012 (stripped)
    • cout size: 12426 (unstriped), 3628 (stripped)
  2. Libs
    • printf
      • libc.so.6
      • /lib/ld-linux.so.2
    • cout
      • libstdc++-libc6.1-1.so.2
      • libm.so.6
      • libc.so.6
      • /lib/ld-linux.so..2
  3. page faults
    • printf: 100
    • cout: 147

Quick and dirty? Well, certainly quick, hardly dirty. I must admit it has gotten better... it used to include libcurses when iostream was used. But still, what does it need libm for?

And still, the thought of trying to do this with iostreams scares me.

    sprintf(format,"%%.%ds\n",(ptr>=end_tape)?ptr+1:end_tape);
    printf(format,tape);

I once told my boss "I'll give up printf() when you pry my cold dead fingers from it". Well, he was happy to oblige.

Now I'm not saying that coding without the use of both hands is easy but not having printf() really hurts.
The injury first occured when I started programming on embedded systems. I thought I would never be able to cope. Embedded systems usually = no debugger, which is when I would use printf(). I soon learned that there are ways to get around the problem and get some work done.

Alternatives to printf():

  • Trace
    Some fortunate embedded systems programmers are able to transmit character strings from the hardware to another computer over a serial cable, called trace. This can be quite a sophisticated system usually achieved by calling specialised functions that get the string and send it on. They can even assign priorities and different colours to the trace. Some projects even use specialised software to turn the trace into nicely formatted reports, graphs and other useful presentations.
    A major downside of this method is that the trace always lags behind what is actually going on. Usually because sending out trace happens on different thread and stuff only gets sent out periodically. This means that if the hardware were to crash before all of the trace was out, the trace stays in!
  • JTAG
    For this you need some expensive JTAG hardware to plug onto the board that you are using, and some even more expensive JTAG software to interpret what comes out of the hardware. Essentially JTAG is a standard that defines a special kind of trace that contains data relating to what the software is doing. This allows you to have some kind of rudimentary debugger where you can stop the program and look at the call stack and the contents of any variables in scope.
    You guessed it, it's still not perfect. This kit is expensive. A price is usually decide by picking a number between 3 and 6 then putting another number in front of that many zeros. Not only this but,it's just not a proper replacement for a real debugger. JTAG is only really a standard for the hardware compatability, the power (or lack thereof) lies in the software. Some only allow you to set a single break point in the software and after a program has been stopped, you can't start back where you left it. Also, since you are just using glorified trace, the device can still crash and tell you nothing, not matter where you stick your break points! This is far from convenient. Lastly, not all embedded devices support JTAG!
  • X debugging
    Last, but not least, the exact embedded equivelant of printf() debugging. When all else fails, you can still add some code that makes a sound or flashes a light. The X is anything that can act as an output and serves as a signal that your program has reached a certain point in the code. If you are fortunate to have a selection of lights or sounds then the debugging will go a lot quicker but a lot can be achieved with just 1.

None of the above will ever replace a fully functioning printf() statement so I will remain a printf() amputee for the forseeable future.

Log in or register to write something here or to contact authors.