0

I'm writing a program, and I would like to output different types of debugging information depending on the value of various macro variables (so that I can change the value of a flag that then causes different levels of information to be written to the screen).

For example, suppose I have the following code that prints information to the screen about my program (call this D1):

cout << "% Percentage complete: "
     << ceil((static_cast<double>(idx)/static_cast<double>(ITERATIONS))*(100.00))
     << "%" << endl;
cout << "x = [ x; ";
for(int i=0; i<space.getDimension(); i++)
    cout << visited.vec[visited.bestIndex].x[i] << "\t";
cout << "];" << endl;

Now, also suppose I have the following code that prints different information to the screen about my program (call this D2):

cout << "best = [ best; "
     << visited.vec[visited.bestIndex].meanQALY() << "];\n" << endl;
space.displayConstraintsMATLAB(idx+1);

I would like to be able to insert statements such as #D1 and #D2 at certain places in my code and have the macro processor replace these statements with the above code blocks.

How can I do this?

(I'm happy to hear suggestions for different ways of doing this, if macros are not an ideal solution.)

moooeeeep
  • 31,622
  • 22
  • 98
  • 187
synaptik
  • 8,971
  • 16
  • 71
  • 98
  • You mean like `#define FOO`, `#ifdef FOO *codeblock* #endif`? – Dennis Meng Aug 10 '12 at 16:49
  • @DennisMeng Yes, like that precisely. And (but) that when I read my code, I don't want to have to keep looking at blocks of debug-related code. I'd prefer to just see a statement where debug-related code goes. – synaptik Aug 10 '12 at 16:49
  • Well, you *could* do a large `#define`, but that just feels wrong... – Dennis Meng Aug 10 '12 at 16:52
  • 1
    Why not just get an editor with code folding? – Carl Norum Aug 10 '12 at 16:53
  • @CarlNorum well, that's a possible solution. – synaptik Aug 10 '12 at 16:54
  • Many logging libraries have already resolved that and more complex problems. I suggest that you pick your choice of logger and just use it. – David Rodríguez - dribeas Aug 10 '12 at 16:55
  • @DavidRodríguez-dribeas I don't know anything about loggers. Never heard the term (in this context). After a quick Google of "logging library", it seems that these are designed specifically for printing information about a program. I will look into this more... – synaptik Aug 10 '12 at 16:59
  • @synaptik For simple programs logging can be overkill. For large programs a good logging library is essential. – Pyrce Aug 10 '12 at 16:59
  • @Pyrce Ahh, well my program is simple. The algorithm it implements is complex, but the program doesn't have to interface with a UI or other systems, and I don't care about input validation. It's just about solving an optimization problem. So, maybe logging is overkill here. – synaptik Aug 10 '12 at 17:01
  • @synaptik Then I would say a simple `#define DEBUG(var) ...` would be the quickest solution to seeing some debug statements while you're still testing. You'll probably even want to remove them once it's fully functional and debugged. – Pyrce Aug 10 '12 at 17:04
  • possible duplicate of [Is this a good way to embed debugging message in my program? (Macros)](http://stackoverflow.com/questions/11480463/is-this-a-good-way-to-embed-debugging-message-in-my-program-macros) – moooeeeep Aug 10 '12 at 17:24
  • have a look at this answer: http://stackoverflow.com/a/11480580/1025391 – moooeeeep Aug 10 '12 at 17:27

2 Answers2

1

You can either make a macro which does debugging for you -- like:

#ifdef D1
#    define DEBUG(var) //Debug 1 print implementation here
#elif defined D2
#    define DEBUG(var) //Debug 2 print implementation here
#else
#    define DEBUG(var) //No-op
#endif

Otherwise you could make a debug function, then inside of that function do a similar check with #if def statements to see how you want to process the input. The function version has a little more early type detection so it tends to tell you about errors in a nicer fashion when you try printing something that's not processable (some custom object). Additionally if the function is a no-op (has no internals in Release mode) then the function call will be discarded by your compiler when any optimization flags are present, so you won't pay any additional cost in Release mode as a result of Debug calls.

For my own debug calls I usually defined a stream operator, much like std::cout, to convert all the inputs to strings or char* and then punt them to a a debug function if DEBUG is defined or print nothing. For exceptions and logging you can do a similar metric with varying levels of severity (Info, Warning, Error, etc). This tends to make it as easy to throw debug code around in C++ as it is in more modern languages imo.

Pyrce
  • 8,296
  • 3
  • 31
  • 46
  • I must suggest that you use both, the function provides a good type checking, while the macro makes sure, that when you build in Release mode, the debug code won't slow down your program. something like #ifdef DEBUG #define LOG(r) log(r) #else #define LOG(r) /*nothing*/ #endif – Evan Dark Aug 10 '12 at 17:22
  • @EvanDark Sorry if I wasn't clear, my second suggestion was exactly that -- function prototypes with internals implemented by #ifdef checks. Which when set to no-ops will be optimized away with opt flags. I'll update the answer to make it clearer. – Pyrce Aug 10 '12 at 18:15
1

Seems to me what you're looking for is a logging facility. Check out this thread for some suggestions.

Why using a whole framework instead of Macros?

The problem is that proper logging is more difficult than it seems. There are threading issues, sessions, classes and object instances are factors you have to consider. Also log file buffering, roll over and compressing log files are issues you have to think about. You might also want to log over the network or to syslog (or both), or into a database. Correctly implementing all of this yourself is a lot of work.

Are Macros any good?

Sure! In our project we have defined a single macro called LOG which wraps calls to our logging framework (we're using log4cpp). If one day we device to move to another framework, we only have to redefine our LOG macro in a single place instead of combing the entire codebase. This works because most logging frameworks share a similar interface usually consisting of the log-level and the message string.

Community
  • 1
  • 1
djf
  • 6,592
  • 6
  • 44
  • 62