5

by design, in the environment I'm working right now I can't use a debugger to try to detect bugs, so pretty much always when I need to debug a functionality I end up outputting some info.

To do that I've done the following:

#ifdef DEBUG
    #define printd(x) printf x
#else
    #define printd(x)
#endif

So when I need to print some debug info I use printd() instead of printf().

The problem I've found is that I need a leveled system, there are messages that may be important in a determined debug level, but irrelevant when debugging other parts of the code.

So my question is, how can I implement a leveled debug system? I value simplicity, I mean, I prefer my actual system than needing a lot of code or confusing code when using it. Something like printd(level, format, ...) would be awesome.

Carla Álvarez
  • 1,077
  • 3
  • 10
  • 9

3 Answers3

7

Sure, there are more elegant ways to do this, of course, but this works just fine

#ifdef DEBUG
 extern int g_debuglevel;
 #define printd(level, x) (level <= g_debuglevel) ? 0 : printf x
#else
 #define printd(level, x)
#endif

Although personally I prefer this

#ifdef DEBUG
 extern void printdf(level, fmt, ...);
 #define printd printfd
#else
 #define printd
#endif

where printdf is a function that tests the level and then calls vprintf passing along the fmt and va_args.

John Knoeller
  • 33,512
  • 4
  • 61
  • 92
  • 2
    There are sound maintenance reasons for ensuring that the code is always expanded so that the compiler always compiles the debug code. Use `if (0) { ...debug printing...}` or equivalents. It greatly reduces the chance of the debugging being broken when you next activate it - which might be years after the last time. – Jonathan Leffler Feb 02 '10 at 02:46
  • @Johnathon: Actually, I simplified a bit to match the code he posted. my actual debug macro expands to some code whether debug is defined or not. one lesson at a time. – John Knoeller Feb 02 '10 at 02:56
  • @Johnathon: Also, building debug and retail on every checking solves the maintenance issue without the cost of bloating the retail code with debug information. – John Knoeller Feb 02 '10 at 03:10
  • 1
    There is no code bloat in the 'retail' code unless the compiler is broken; it will optimize away the code after 'if (0)'. I can agree with one lesson at a time - though it doesn't hurt to point out that the current lesson is not the final word on the subject. – Jonathan Leffler Feb 02 '10 at 04:02
  • @Johnathon Leffler: that has not been my experience, the optimizer can _usually_ discard the debug code, but it sometimes has trouble when it references variables outside of the debug block. – John Knoeller Feb 02 '10 at 04:07
1

See the answers to:

These will give you a lot of pointers on what to do.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Yes, you can do fancy new things with a C99 compliant compiler, but most of us don't have that yet. – John Knoeller Feb 02 '10 at 02:58
  • @John Knoeller: As I point out in my answer to the first of the two questions listed, there is a perfectly viable solution for C89 which I used until a couple of years ago. It isn't as neat and tidy as the C99 solution using the `__VA_ARGS__` macro arguments, but it most certainly works. – Jonathan Leffler Feb 02 '10 at 03:59
  • Thank you! I've done something similar in the end, and now I now it's better to allow the compiler see debug code in release builds. – Carla Álvarez Feb 02 '10 at 14:15
1

If you want to go the extra step and log your level debug statements they you could try log4c. http://log4c.sourceforge.net/

in the printfd function described above, you can also check for an environment variable say DEBUG_LOG_LEVEL to dynamically switch on and off your logging.

I used a similar technique to implement a lightweight leveled logging library for an embedded linux environment.

Also for an example of log4c - http://log4c.sourcearchive.com/documentation/1.2.1/helloworld_8c-source.html Thanks to google search :)

ka05
  • 594
  • 1
  • 5
  • 12