2

I'm trying to create a macro for debug logging purposes. Here is an extra simplified version:

#if defined _DEBUG
#define LOG std::cout
#else
#define LOG IGNORETHISLINEOFCODE
#endif

/* ... */

LOG << "Here's some debug code";

I've been thinking of the ways I can tell the compiler to ignore this line of code that starts with "LOG". I'm personally not looking for alternative ways, such as #define LOG( ... ) (void)0. Here's what I've tried:

  • Overloading the leftshift operator for void as an inline constexpr that does nothing (which still results in it being visible in the disassembly; I don't want that)

  • Defining LOG as: #define LOG //, but the comment identifier isn't substituted in

Any ideas? Like I said earlier, I don't want any alternatives, such as surrounding all the log code with #if defined _DEBUG

Cryptography Man
  • 189
  • 2
  • 10
  • 1
    http://www.drdobbs.com/cc-tip-5-a-cc-comment-macro/184401344 might be of interest for you? – Claus Jørgensen Oct 07 '18 at 22:02
  • If you're only concerned with `cout`, couldn't you just redirect the stream to nothing? https://stackoverflow.com/questions/8246317/redirecting-function-output-to-dev-null – Tas Oct 07 '18 at 22:03
  • @ClausJørgensen that is VERY interesting! Will look into utilizing/testing it – Cryptography Man Oct 07 '18 at 22:05
  • @Tas unfortunately, the objective is to just have the code not even be recognized by the compiler. It's a good idea and would work if I didnt have such specific constraints :( – Cryptography Man Oct 07 '18 at 22:06
  • *"tell the compiler to ignore this line of code ... I'm personally not looking for alternative ways"* It's most likely impossible. What you can do is to make a class with a no-op overloaded `<<`. Those lines will still be processed, but any decent compiler with optimizations enabled should emit no code for them in most cases. – HolyBlackCat Oct 07 '18 at 22:14
  • Why such an odd requirement? – Carey Gregory Oct 07 '18 at 22:48
  • @CareyGregory my debug info can be used to reverse engineer my program. just trying to make it not super easy :) – Cryptography Man Oct 07 '18 at 23:57
  • @CareyGregory this'll work :) post it as an answer – Cryptography Man Oct 07 '18 at 23:58

5 Answers5

4

If your version of C++ handles if constexpr I've come to like things along this line for what you're asking.

#include <iostream>

template <bool Log>
struct LOGGER {
    template <typename T>
    LOGGER& operator<<(T const &t) {
        if constexpr (Log)
            std::cout << t;
        return *this;
    }
};

LOGGER<false> LOG;

int main (int argc, char const* argv[])
{
    LOG << "A log statement." << '\n';
    return 0;
}
Richard
  • 8,920
  • 2
  • 18
  • 24
  • the disassembly shows the object trace, but this is pretty good because it doesn't actually reveal any objects pushed to the logger stream. – Cryptography Man Oct 07 '18 at 23:56
  • That is true. It also won’t work with other manipulators. If you want a full implementation it will take a little more effort to write those methods, just as would be the case for many other stream specializations one might write. That effort is left as an exercise for those who wish to use the technique. – Richard Oct 08 '18 at 12:31
2

Your question and constraint ("I don't want any alternatives") are weirdly specific.

I've been thinking of the ways I can tell the compiler to ignore this line of code that starts with "LOG"

Don't do that, it'll be trivially broken by a multi-line logging statement. Any code that can suddenly break due to otherwise-legal reformatting is best avoided.

Next we have

... which still results in it being visible in the disassembly ...

which shouldn't be true if the code is genuinely dead, you have a decent compiler, and you turn on optimization. It's still some work, though.

The usual solution is something like

#ifdef NDEBUG
#define LOG(EXPR)
#else
#define LOG(EXPR) std::cerr << EXPR
#endif

This is an alternative, but it's not an alternative such as surrounding all the log code with #if defined, so I don't know if it's a problem for you or not.

It does have the advantage of genuinely compiling to nothing at any optimization level.

Useless
  • 64,155
  • 6
  • 88
  • 132
2

another possibility based on the compiler optimization abilities:

#define LOG if (DEBUG) std::cout

now you can use

#define DEBUG false
LOG << "hello " << " world 1" << endl;

you should be able to use const bool DEBUG = false as well.

Serge
  • 11,616
  • 3
  • 18
  • 28
0
#if defined _DEBUG
#define LOG std::cout
#else
#define LOG /##/
#endif

This works as well. It's the answer to the original question, so I'll mark it as such, but just know that this does not support multiline operations.

I suppose you could do something like the following for multiline operations. I don't know how well it'd work.

#if defined _DEBUG
#define LOG( in ) std::cout << in
#else
#define LOG( in ) /##/
#endif
Cryptography Man
  • 189
  • 2
  • 10
-1

Better logic would be to define tracer policy, where you can set the logging level at the start of the application and then use the tracing level to make the decision to either log the degug information. Tracing level can be defined as an enum like

enum Tracelevel{CRITICAL, ERROR, INFO, TEST, DEBUG};

setTraceLevel(TraceLevel trcLvl){
    _traceLevel = trcLvl;
};

#if defined _DEBUG
if(_traceLevel  == DEBUG) {\
#define LOG std::cout
}
#endif

A lightweight logger can be found http://www.drdobbs.com/cpp/a-lightweight-logger-for-c/240147505?pgno=1

Jolly Jose
  • 84
  • 5