jensa
jensa

Reputation: 2890

Standard way for writing a debug mode in C++

Is there a "best practice" or similar for coding in a debug-mode in one's code? For example,

#include <iostream>

int main()
{
    #ifdef MY_DEBUG_DEF
    std::cout << "This is only printed if MY_DEBUG_DEF is defined\n";
    #endif

    return 0;
}

Or is this considered bad practice because the code gets bit messier? I have noticed some libraries (for example libcurl, which is a large and well-known library) have this feature; if you define VERBOSE with libcurl you get basically a debug mode

Thank you.

Upvotes: 3

Views: 2525

Answers (4)

Mats Petersson
Mats Petersson

Reputation: 129374

I personally prefer runtime enabled logging. That means that you don't have to recompile to get the "debug output". So I have a command-line argument -v=n, where n defaults to zero, and gets stored in the variable verbosity in the actual program. With -v=1 I get basic tracing (basic flow of the code), with -v=2 I get "more stuff" (such as dumps of internal state in selected functions). Two levels is often enough, but three levels may be good at times. An alternative is to make verbosity a bit-pattern, and enable/disable certain functionality based on which bits are set - so set bit 0 for basic trace, bit 1 gives extra info in some module, bit 2 gives extra trace in another module, etc. If you want to be REALLY fancy, you have names, such as -trace=all_basic, -trace=detailed, -trace=module_A, -trace=all_basic,module_A,module_B or some such.

Combine this with a macro along the lines of:

 #define TRACE do { if (verbosity > 0) \ 
       std::cout << __FILE__ << ":" << __LINE__ << ":" \
                 << __PRETTY_FUNCTION__ << std::endl; } while(0)

For things that may take a substantial amount of extra time, such as verifying the correctness of a large and complex data structure (tree, linked list, etc), then using #ifndef NDEBUG around that code would be a good thing. Assuming of course you believe that you'll never mess that up in a release build.

Real livig code here: https://github.com/Leporacanthicus/lacsap/blob/master/trace.h https://github.com/Leporacanthicus/lacsap/blob/master/trace.cpp being use here for example: https://github.com/Leporacanthicus/lacsap/blob/master/expr.cpp

(Note that some simple functions that get called a lot don't have "TRACE" - it just clutters up the trace and makes it far too long)

Upvotes: 1

A more usual way is to follow conventions from assert(3): wrap with #ifndef NDEBUG .... #endifcode which is only useful for debugging, and without any significant side effects.

You could even add some debug-printing macro like

extern bool wantdebug;
#ifndef NDEBUG
#define OUTDEBUG(Out) do { if (wantdebug) \
   std::cerr << __FILE__ << ":" << __LINE__ \
             << " " << Out << std::endl; \
} while(0)
#else
#define OUTDEBUG(Out) do {}while(0)
#endif

and use something like OUTDEBUG("x=" << x) at appropriate places in your code. Then wantdebug flag would be set thru the debugger, or thru some program arguments. You probably want to emit a newline and flush cerr (or cout, or your own debug output stream) -using std::endl ...- to get the debug output displayed immediately (so a future crash of your program would still give sensible debug outputs).

Upvotes: 4

Like
Like

Reputation: 1536

Using logger may be better, e.g.

The above are very flexible, but heavyweight. You can also implement some simple macros instead:

#ifdef NDEBUG
#define DBG(FMT, ...)
#else // !NDEBUG
#define DBG(FMT, ...) fprintf (stderr, FMT, ## __VA_ARGS__)
#endif // NDEBUG

The above is GCC syntax from Macros with a Variable Number of Arguments. For VC, please see also How to make a variadic macro (variable number of arguments)

Upvotes: 0

David
David

Reputation: 4873

That is an acceptable method. Yes, it gets messy, but it makes it a lot easier to debug as well. Plus you can normally collapse those kinds of things, thus removing the messiness.

As you've mentioned, libcurl uses the method. I also used to have a teacher who works for HP on their printer software, and they used the same method.

Upvotes: 1

Related Questions