我正在尝试做一个调试系统,但它似乎无法正常工作。
我的目标是实现以下功能:
#ifndef DEBUG
#define printd //
#else
#define printd printf
#endif
有没有一种方法可以实现这个?我有许多调试消息,我不想这样做:
if (DEBUG)
printf(...)
code
if (DEBUG)
printf(...)
...
我正在尝试做一个调试系统,但它似乎无法正常工作。
我的目标是实现以下功能:
#ifndef DEBUG
#define printd //
#else
#define printd printf
#endif
有没有一种方法可以实现这个?我有许多调试消息,我不想这样做:
if (DEBUG)
printf(...)
code
if (DEBUG)
printf(...)
...
不能。在开始任何预处理指令的处理之前,注释将从代码中删除。因此,您无法将注释包含在宏中。
此外,通过使用任何宏技巧“形成”注释的任何尝试都不能保证有效。编译器不需要将“延迟”的注释视为注释。
实现您想要的最佳方法是在C99中使用具有可变参数的宏(或者可能使用编译器扩展)。
一个常见的技巧是这样做:
#ifdef DEBUG
#define OUTPUT(x) printf x
#else
#define OUTPUT(x)
#endif
#include <stdio.h>
int main(void)
{
OUTPUT(("%s line %i\n", __FILE__, __LINE__));
return 0;
}
这种方式使您可以完全使用printf()
的功能,但您必须忍受双括号以使宏起作用。
双括号的目的是:需要一个括号集来表示它是宏调用,但在C89中,宏中不能有不确定数量的参数。但是,通过将参数放在自己的一组括号中,它们会被解释为单个参数。当定义了DEBUG
时,宏展开时,替换文本是单词printf
后跟单个参数,该参数实际上是几个带括号的项。然后,这些括号被解释为printf
函数调用中需要的括号,因此它可以正常工作。
使用C99方式:
#ifdef DEBUG
#define printd(...) printf(__VA_ARGS__)
#else
#define printd(...)
#endif
好的,这个不需要C99但是假设编译器已经针对发布版本进行了优化:
#ifdef DEBUG
#define printd printf
#else
#define printd if (1) {} else printf
#endif
在某些编译器上(包括MS VS2010),这将起作用,
#define CMT / ## /
但并不保证所有编译器都能正常运行。
printf_debug
,并将DEBUG
放置在此函数内部。编译器会优化空函数。</p>
。#ifndef DEBUG
#define printd(fmt, ...) do { } while(0)
#else
#define printd(fmt, ...) printf(fmt, __VA_ARGS__)
#endif
这样,当你在末尾添加一个分号时,它会按照你的意愿执行。由于没有操作,编译器将编译掉“do...while”。
if
。例如,#ifdef debug
#define printd printf
#else
#define printd if (false) printf
#endif
-O2
这样的优化标志,编译器将删除这些无法访问的代码。这种方法对于std::cout
也很有用。未经测试: 编辑:已经测试,现在我自己在使用它 :)
#define DEBUG 1
#define printd(fmt,...) if(DEBUG)printf(fmt, __VA_ARGS__)
需要你不仅定义DEBUG
,还要给它一个非零值。
附录:
也可以与std::cout
很好地配合使用。
#ifndef NDEBUG
constexpr bool DEBUG = true;
#else
constexpr bool DEBUG = false;
#endif
if constexpr (DEBUG) /* debug code */
需要注意的是,与预处理器宏不同,您的作用范围受到限制。您不能在一个调试条件中声明变量并从另一个条件中访问它们,也不能在函数外部作用域中使用它们。
//
替换printd
,你会遇到问题。相反,你可以使用可变参数宏来将printd
替换为一个什么也不做的函数,如下所示。#ifndef DEBUG
#define printd(...) do_nothing()
#else
#define printd(...) printf(__VA_ARGS__)
#endif
void do_nothing() { ; }
使用像GDB这样的调试器也可能有所帮助,但有时候一个快速的printf
就足够了。
#ifdefs
的情况下从生产代码中剥离代码,由于 OP 的次要问题,我找到了一些设想,使我走上了正确的轨道。我不会搜索“调试打印”的问题 - 那根本不是我的用例! - Username Obfuscation