由变量控制的C ++调试宏

时间:2014-03-28 13:50:17

标签: c++ debugging variables macros

我正在编写一个C ++程序,我正在尝试包含一个由宏控制的调试消息传递方法,只有在创建拥有调试方法的对象的运行时设置调试标志时才会调用该方法。性能很重要,所以我尝试不调用调试消息传递代码,如果不需要它,而不是编译程序的两个不同版本,一个用调试宏,另一个用没有。

直到现在我才尝试这样的事情:

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;
    }
}

我使用掩码仅在运行时的特定时刻显示调试信息,或仅用于类的特定对象。一切似乎都正常,因为如果flag为0,它不会输出任何消息,但我发现在定义DEBUG时它并不重要,这个程序总是定义DEBUG。如果标志为0,则不会打印任何内容,但无论如何都会调用调试方法并执行检查,这意味着性能松散。

我也试过类似下面的例子,以保持我的代码结构:

#define FLAG flag

#if FLAG>0
    #define DEBUG
#endif

但在这种情况下,无论flag的值如何,#if都会返回false。

我甚至尝试过:

const int flag2 = flag;
#define FLAG flag2

#if FLAG>0
    #define DEBUG
#endif

与上面的例子结果相同。 我的问题是:有没有办法根据变量的值定义宏?欢迎任何想法,但请记住,我希望保持这种结构。否则就意味着如果代码行改变数千。

谢谢大家,伙计。

5 个答案:

答案 0 :(得分:2)

预处理在编译器看到代码之前完成,因此DEBUG在编译时就消失了。

也许您可以更改调试功能:

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;
      }
    }
}

然后在调用代码中,设置此全局标志:

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

答案 1 :(得分:2)

  

我的问题是:有没有办法根据变量的值来定义宏?

没有。您可以定义要替换为该变量的宏,但不能根据变量值定义要定义宏的宏。因为在预编译期间会对宏进行求值,所以在运行程序之前(或换句话说,在变量初始化之前很久并且有值),所有宏都将被定义或不长。

  

欢迎任何想法,但请记住,我希望保留这种结构。否则就意味着如果代码行改变数千。

试试这个:

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
}

如果定义了DEBUG宏,则将使用以下源编译此代码:

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;
    }
}

如果没有定义宏,代码将使用此源编译:

unsigned int flag = 0xFFFFFFFF;

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

或者,您可以定义日志记录宏以避免完全调用该函数:

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

通过这种方式,当未定义DEBUG时,所有DBGLOG调用都将评估为空白源代码行(它没有比这更有效)。

关于您的效率问题的说明:除非您有极高的效率要求,否则记录调用的性能可能无关紧要。要确定它们是否重要,首先设定一个目标(“我希望应用程序没有明显的延迟”,“我希望每秒处理150条消息”等),然后通过强调应用程序来测量性能(即运行测试的部分1000时间左右,测量经过的时间,然后除以1000),然后找出性能最差的违规者,并对其进行优化。

优化代码级别的性能(即非架构或算法设计)设置性能目标和衡量当前性能之前 过早优化。 您很有可能在没有目标和测量(包括加速记录)的情况下进行的任何优化工作都只是浪费了开发时间。

答案 2 :(得分:1)

您无法在运行时控制预处理器。编译程序时,首先运行预处理程序,然后处理所有预处理程序标记。然后编译器只编译生成的代码。

如果要在运行时决定是否要调用调试函数,则必须使用普通的if语句。我的建议是尽可能将调试代码保持在一起,以使用单个if语句启用/禁用它。

答案 3 :(得分:1)

以@metal解决方案为基础。

我的建议如下:

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

其中debug()是@metal定义的调试函数.... 你可以用

DEBUG("This is a trace");

这样一来,当曲目关闭时,你不会因函数调用而付出代价。

答案 4 :(得分:0)

您只需要一个标志来确定是否将调试消息发送到某个地方(即.stdout,file等)。该标志可以是全局布尔变量。然后,您可以定义一个宏DEBUG(...),其中包含用于检查标志的代码,并在标志为真时进行调试。

现在的挑战是能够在运行时调整此标志。您可以使用单独的逻辑来查找当前运行目录中是否存在文件(即debug.cfg)。如果存在,请将global标志更改为true。否则,设置为false。

通过这个简单的事情,要启用调试,只需在相应的目录中创建一个文件即可。要禁用调试,请删除该文件。

完成此操作后,您可以通过debug.cfg包含信息来进一步增强调试功能。您可以做的一些事情是调试级别(即INFO,ERROR,WARNING等)或仅针对特定代码区域(即类名)启用调试。