0

I would have assumed this would be a widely asked question, but still I have yet to find an answer.

I was debugging some C++ code that was creating errors in a subtle way only with certain function handles as inputs. Long story short fixed the problem but I defined in the .cpp file:

#define DEBUG(x) do { std::cerr << x << std::endl; } while (0)

needless to say the code is littered with:

DEBUG("Foo's address") 
DEBUG(&Foo)

Now I assumed that in "Release" that the compiler would ignore all these pre-compiler outputs. But it doesn't!

So how does one do this in practice (I want to leave the outputs for future additions, but obviously don't want it in release versions)? I'm trying out clion which uses cmake, is this something IDE/compiler specific?

Thanks

Chris
  • 362
  • 6
  • 16
  • You would probably want something like `#define DEBUG(x) do { } while(0)` defining in Release builds. You then conditionally define one or the other depending on which build-mode you're in. Predefined identifiers for this probably are IDE/compiler specific. – TripeHound Aug 06 '15 at 16:03
  • Why do you think it should go away in the release build automatically? You have defined this macro unconditionally. – πάντα ῥεῖ Aug 06 '15 at 16:04
  • @πάνταῥεῖ now that you mention it, probably due to the fact that I its called DEBUG lol, I'm not that experienced with precompiler directives, It was probably a dumb assumption.. – Chris Aug 06 '15 at 16:10
  • @TripeHound yea I could do that, but I wanted something a little more elegant that changed the compiler output automatically depending on whether it was "Release" or "Debug" in the compiler options. – Chris Aug 06 '15 at 16:17

3 Answers3

3

Depending on your compiler it may define something that tells you that compilation is in debug mode (or you can do that yourself on the command line), then:

#ifndef _DEBUG // works in VS
#define DEBUG(x) 
#else
#define DEBUG(x) do { std::cerr << x << std::endl; } while (0)
#endif

For more discussion on which macro to use, see this question.

Community
  • 1
  • 1
Alexander Balabin
  • 2,055
  • 11
  • 13
  • what exactly does the ' _DEBUG ' do? – Chris Aug 06 '15 at 16:19
  • I think the answer's back to front ... if in `_DEBUG` mode, it defines `DEBUG(x)` as nothing, otherwise it defines it as a print. Swap the two `#define`s and try again. – TripeHound Aug 06 '15 at 16:20
  • The `_DEBUG` (use back-quote \` to highlight code) is the "something" that your compiler/IDE/make-system defines in Debug Build but doesn't in Release Builds. This example is for Visual Studio; if your environment doesn't have one, you will need to engineer the build process to include something like it in a debug build (e.g. `$(CC) ... -D_DEBUG ...`). – TripeHound Aug 06 '15 at 16:21
  • @TripeHound, indeed it was btf, fixed now with `ifndef` – Alexander Balabin Aug 06 '15 at 16:24
  • @TripeHound thanks for your help, you were correct the `DEBUG(x)` was defined backwards. On top of that I'm not sure if it's specific to clion which uses CMake but the debug pre-processor directive is `#ifndef NDEBUG`. If you want to write that in an answer I can mark it as the correct one, or I can write one up whatever you prefer. – Chris Aug 06 '15 at 16:36
  • I think Cem's answer covers it in what appears the most portable way (although as the linked thread mentions, it's not standardised) – TripeHound Aug 06 '15 at 16:53
1

Portable way of doing this would be using NDEBUG

#ifdef NDEBUG
#define DEBUG(x) 
#else
#define DEBUG(x) do { std::cerr << x << std::endl; } while (0)
#endif

See: C / C++ : Portable way to detect debug / release?

Community
  • 1
  • 1
Cem Kalyoncu
  • 14,120
  • 4
  • 40
  • 62
1

It is usually a mistake to eliminate logging messages in so-called "release versions". After all, "release versions" are where you will need the logged information most! How else will you even hope to analyse and fix the problem when the end user will tell you nothing but "it doesn't work" or "it crashed"?

So instead of eliminating the valuable information that your software creates to aid you in your bugfixing sessions, think about how to save and persist it such that it can be easily transmitted to you by the end user if problems arise. Like, redirecting the log messages to a log file when the application runs on the user's machine (perhaps with the application itself offering a "Send log file to support" feature, or something like that).

Code like

DEBUG("Foo's address") 
DEBUG(&Foo)

should be replaced with something like:

Log("Foo's address");
Log(std::to_string(&Foo));

Then inside of your Log function, which may have a signature like void Log(std::string const& message), you can check your DEBUG macro and act accordingly:

    void Log(std::string const& message)
    {
#ifdef DEBUG
        // write message to std::cerr
#else
        // write message to log file
#endif
    }

Now, of course, DEBUG is not a standard macro (unlike NDEBUG, which turns assert on and off). It's not implicitly defined. You have to define it yourself when you invoke your compiler. For example, /DDEBUG with MSVC or -DDEBUG with GCC. Chances are that your IDE adds such a flag, or something similar like -D_DEBUG when it runs the compiler, but still, that's not standard and not part of the compiler itself. (Actually, you might consider a different name for the macro anyway if you are going to use it like this, something like LOG_TO_CONSOLE.)

In any case, this is just to give you an inspiration of what do do. You may prefer a std::ostream-based approach instead of a function taking a std::string. There are a lot of questions and answers on Stackoverflow about this.

The important point is: Don't throw away valuable log information under the assumption that you won't need it once your software is released. There will be bugs and vague error descriptions.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62