Ah the great feeling when, after days of work, your program finally compiles. There's nothing as rewarding as going through and checking off every cryptic "Symbol % not expected before or after ^ unless this is an odd numbered Tuesday or your last name beings with W" error message.
So now you have your compiled program; you run it... and nothing. DOA. Or worse, it does something you didn't expect. (I heard a tale this week of a program that read in and displayed user input, but was accidentally off by one: enter a, get garbage, enter b, get a) So then the question is: How do you go about dissecting this program and figuring out where the computer didn't understand what you meant? (aka you f%$&ed up) My solution is slapping this bit of code at the beginning of every program I write:
#define ErR(a) fprintf(stderr, "%s\n", a)
#define ErR(a) fprintf(stderr, "%s\n", a); sleep(1)
It may look nasty, but that's only because the C preprocessor lacks an elseifdef scenario. In reality, this bit of code works magic. Everywhere in code that I think would be of interest, I simply add:
ErR("Debugging message here");
And go about my business. Then when I got to compile the program, the real magic begins.
When compiling, there is a way to define symbols for the preprocessor from the command line with the -D flag. As can be seen in the snippet above, if DEBUG is defined, it will replace every ErR with a fprintf and display the message. If DEBUG_SLOW is defined, it will replace ErR with a fprintf, as well as adding in a one second pause at each message.
Sample code - hello.c:
ErR("Beginning of program");
ErR("End of program");
cc -o hello hello.c -DDEBUG
Beginning of program
End of program
cc -o hello hello.c -DDEBUG_SLOW
Beginning of program *pause*
End of program *pause*
Granted, this debugging macro only works for flow control problems, which is usually my problem. If you're expecting a function to call another function only every third time, with this it will be real easy to watch to see how many times the second function gets called. Then when you're done debugging, just compile the code without DEBUG or DEBUG_SLOW defined, and all the debug info goes away with no performance hit.
An extension to this would be to let the programmer call ErR with more arguments to display along with the message:
ErR("Current location: ", x, y);
But I rarely need more than the basic message. Just need to see how far the program gets before segmentation faulting.