Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

increase c++ code verbosity with macros

I'd like to have the possibility to increase the verbosity for debug purposes of my program. Of course I can do that using a switch/flag during runtime. But that can be very inefficient, due to all the 'if' statements I should add to my code.

So, I'd like to add a flag to be used during compilation in order to include optional, usually slow debug operations in my code, without affecting the performance/size of my program when not needed. here's an example:

/* code */
#ifdef _DEBUG_
/* do debug operations here 
#endif

so, compiling with -D_DEBUG_ should do the trick. without it, that part won't be included in my program.

Another option (at least for i/o operations) would be to define at least an i/o function, like

#ifdef _DEBUG_
#define LOG(x) std::clog << x << std::endl;
#else
#define LOG(x) 
#endif

However, I strongly suspect this probably isn't the cleanest way to do that. So, what would you do instead?

like image 707
MarcDuQuesne Avatar asked Feb 11 '13 13:02

MarcDuQuesne


3 Answers

I prefer to use #ifdef with real functions so that the function has an empty body if _DEBUG_ is not defined:

void log(std::string x)
{
#ifdef _DEBUG_
  std::cout << x << std::endl;
#endif
}

There are three big reasons for this preference:

  1. When _DEBUG_ is not defined, the function definition is empty and any modern compiler will completely optimize out any call to that function (the definition should be visible inside that translation unit, of course).
  2. The #ifdef guard only has to be applied to a small localized area of code, rather than every time you call log.
  3. You do not need to use lots of macros, avoiding pollution of your code.
like image 124
Joseph Mansfield Avatar answered Oct 14 '22 15:10

Joseph Mansfield


You can use macros to change implementation of the function (Like in sftrabbit's solution). That way, no empty places will be left in your code, and the compiler will optimize the "empty" calls away.

You can also use two distinct files for the debug and release implementation, and let your IDE/build script choose the appropriate one; this involves no #defines at all. Just remember the DRY rule and make the clean code reusable in debug scenario.

I would say that his actually is very dependent on the actual problem you are facing. Some problems will benefit more of the second solution, whilst the simple code might be better with simple defines.

like image 20
Bartek Banachewicz Avatar answered Oct 14 '22 15:10

Bartek Banachewicz


Both snippets that you describe are correct ways of using conditional compilation to enable or disable the debugging through a compile-time switch. However, your assertion that checking the debug flags at runtime "can be very inefficient, due to all the 'if' statements I should add to my code" is mostly incorrect: in most practical cases a runtime check does not influence the speed of your program in a detectable way, so if keeping the runtime flag offers you potential advantages (e.g. turning the debugging on to diagnose a problem in production without recompiling) you should go for a run-time flag instead.

like image 31
Sergey Kalinichenko Avatar answered Oct 14 '22 16:10

Sergey Kalinichenko