0

I am coding a C++ program and I am trying to include a debug messaging method controlled by a macro which is only called when a debugging flag is set in run time when creating the object which owns the debugging method. The performance is important, so I am trying the debug messaging code not to be called if it is not needed, instead of compiling two different versions of the program, one with debugging macro and another one without.

Until now I was trying something like this:

unsigned int flag = 0xFFFFFFFF;

if (flag != 0)
{
    #define DEBUG
}

#ifdef DEBUG
     debug("This is call 1 to the debug method");
#endif

#ifdef DEBUG
    debug("This is call 2 to the debug method");
#endif



debug(std::string message) 
{
    if ((flag && MASK_I_DEFINED_SOMEWHERE_FOR_STUFF) != 0)
    {
         std::cout << message << std::endl;
    }
}

I use masks to show debugging information only in specific moments of the run time, or only for specific objects of the class. Everything seemed to work right, because if flag is 0, it does not output any message, but I found out that it doesn't matter the value of flag when defining DEBUG, this program always defines DEBUG. If the flags are 0, it does not print anything, but the debug method is called anyway and the checks are performed, which means a loose in performance.

I also tried with something like the following example, to keep the structure of my code:

#define FLAG flag

#if FLAG>0
    #define DEBUG
#endif

But in this case, the #if returns always false, no matter the value of flag.

I even tried with:

const int flag2 = flag;
#define FLAG flag2

#if FLAG>0
    #define DEBUG
#endif

with same results as the example above. My question is: Is there a way of defining a macro depending on the value of a variable? Any ideas are welcome, but please keep in mind that I would like to keep this structure. Otherwise it would mean changing thousands if lines of code.

Thank you all, guys.

1
  • 4
    The handling of pre-processor directives such as #define happen even before compilation, during the pre-processing step. You cannot affect this at run-time. Commented Mar 28, 2014 at 13:54

5 Answers 5

2

My question is: Is there a way of defining a macro depending on the value of a variable?

No. You can define a macro to be replaced with that variable, but not to make it so that the macro is defined or not, based on the variable value. Because macros are evaluated during pre-compilation, all macros will be defined or not long before you run the program (in other words, long before your variables are initialized and have a value).

Any ideas are welcome, but please keep in mind that I would like to keep this structure. Otherwise it would mean changing thousands if lines of code.

Try this:

unsigned int flag = 0xFFFFFFFF;

void debug(const std::string& message) // const & for efficiency
{
#ifdef DEBUG
    if ((flag && MASK_I_DEFINED_SOMEWHERE_FOR_STUFF) != 0)
    {
        std::cout << message << std::endl;
    }
#endif
}

When you have the DEBUG macro defined, this code will be compiled using the following source:

unsigned int flag = 0xFFFFFFFF;

void debug(const std::string& message) // const & for efficiency
{
    if ((flag && MASK_I_DEFINED_SOMEWHERE_FOR_STUFF) != 0)
    {
        std::cout << message << std::endl;
    }
}

When you do not have the macro defined, the code will be compiled using this source:

unsigned int flag = 0xFFFFFFFF;

void debug(const std::string& message) // const & for efficiency
{
}

Alternately, you can define your logging macro to avoid calling the function alltogether:

#ifdef DEBUG
#    define DBGLOG(x) debug(x)
#else
#    define DBGLOG(x)
#endif

In this way, when DEBUG is not defined, all your DBGLOG calls will evaluate to a blank source line (it doesn't get more efficient than that).

A note regarding your efficiency concerns: Unless you have extreme efficiency requirements, performance of the logging calls should probably not matter. To decide if they matter, first set a goal ("I want the application to have no noticeable lag", "I want 150 messages processed per second", etc), then measure performance by stressing the application (i.e. run the tested part 1000 times or so, measure elapsed time, then divide by 1000), then find the worst performance offenders, and optimize those.

Optimizing for performance at code level (i.e. not architecture or algorithm design) before you set performance goals and measure current performance, is premature optimization. It is highly probable that any optimization effort you make without goals and measurements (including speeding up logging), is simply wasted development time.

Sign up to request clarification or add additional context in comments.

2 Comments

Wooops, I didn't take into account that directives are considered BEFORE compiling, and therefore before run time. You all are totally right. I think this example is what is closer to what I was doing. I'll keep it like this and define/undefine the DEBUG macro depending on the use I want to do to the code. Thanks, guys.
If you allow me. I'm not sure making traces as unobstrusive as possible can be considered premature optimization. Of course, if you're application is small and/or deals mostly with string stuff, I/O or user input it probably doesn't matter. But thinking of medium/big server applications where the amount of tracing code can be important... then tracing code matters and it is code you would like not to be there until you need to enable it to debug a problem. It becomes a matter of best practice, like using the prefix increment or passing read-only parameter as const &
2

Preprocessing is done before the compiler sees the code, so DEBUG is gone at compile-time.

Maybe you can change your debug functions:

bool g_enableDebug = false;

void debug( const std::string& msg ) // note the const ref for efficiency
{
    if( g_enableDebug )
    {
      if ((flag && MASK_I_DEFINED_SOMEWHERE_FOR_STUFF) != 0)
      {
         std::cout << message << std::endl;
      }
    }
}

Then in the calling code, set this global flag:

if (flag != 0)
{
    g_enableDebug = true;
}

Comments

1

You can not control the preprocessor at runtime. When your program is compiled the preprocessor is run first and all preprocessor tokens are processed. Only the resulting code is then compiled by the compiler.

If you want to decide at runtime if you want to call a debug function you have to use a normal if statement. My advice would be to keep the debug code as close together as possible to enable/disable it with a single if statement.

Comments

1

Building on @metal solution.

My recommendation is something like:

#define DEBUG(message) \
if(g_enableDebug) {    \
    debug(message);    \
}

where debug() is the debug function defined by @metal.... That you can use with

DEBUG("This is a trace");

This way you don't incur in the cost of a function call when traces are off..

Comments

0

You only need one flag to determine whether to send the debug message out to somewhere (ie. stdout, file, etc). This flag could be a global boolean variable. You can then define a macro DEBUG(...) that contains code to check the flag and do debugging if the flag is true.

Now the challenge is to be able to tweak this flag during runtime. You could have a separate logic that looks for the presence of a file (ie. debug.cfg) in the current running directory. If present, change the global flag to true. Otherwise, set to false.

With this simple thing, to enable debug, just create a file in the appropriate directory. To disable debug, remove the file.

Once you have this, you could further enhance your debugging features by having the debug.cfg contain information. Some things you could do is the level of debugging (ie. INFO, ERROR, WARNING, etc) or debug only enabled for certain area of code (ie. class name).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.