你可以#define在C中发表评论吗?
我正在尝试做一个调试系统,但它似乎无法工作。
我想要完成的是这样的事情:
#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 int main(void) { OUTPUT(("%s line %i\n", __FILE__, __LINE__)); return 0; }
这样你就可以获得printf()
的全部function,但你必须忍受双括号才能使宏工作。
双括号的要点是:你需要一个集来表示它是一个宏调用,但你不能在C89中的宏中有一个不确定数量的参数。 但是,通过将参数放在它们自己的括号中,它们被解释为单个参数。 当定义DEBUG
时扩展宏时,替换文本是单词printf
后跟singl参数,实际上是括号中的几个项目。 然后括号被解释为printf
函数调用中所需的括号,因此一切正常。
С99方式:
#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
您可以将所有调试调用放在一个函数中,让它调用printf_debug
并将DEBUG
放在此函数中。 编译器将优化空函数。
在一些编译器(包括MS VS2010)上,这将起作用,
#define CMT / ## /
但没有所有编译器的受助者。
标准方法是使用
#ifndef DEBUG #define printd(fmt, ...) do { } while(0) #else #define printd(fmt, ...) printf(fmt, __VA_ARGS__) #endif
这样,当您在末尾添加分号时,它会执行您想要的操作。 由于没有操作,编译器将编译出“do … while”
未经测试:编辑:测试,现在自己使用它:)
#define DEBUG 1 #define printd(fmt,...) if(DEBUG)printf(fmt, __VA_ARGS__)
要求您不仅要定义DEBUG
,还要给它一个非零值。
附录:也适用于std::cout
在C ++ 17中,我喜欢使用constexpr来做这样的事情
#ifndef NDEBUG constexpr bool DEBUG = true; #else constexpr bool DEBUG = false; #endif
那你可以做
if constexpr (DEBUG) /* debug code */
需要注意的是,与预处理器宏不同,您的范围有限。 您既不能在一个可从另一个调用条件中访问的调试条件中声明变量,也不能在外部函数范围内使用它们。
正如McKay所指出的,如果你只是尝试用//
替换printd
,你会遇到问题。 相反,您可以使用variadric宏将printd
替换为不执行任何操作的函数,如下所示。
#ifndef DEBUG #define printd(...) do_nothing() #else #define printd(...) printf(__VA_ARGS__) #endif void do_nothing() { ; }
使用像GDB这样的调试器也可能有所帮助,但有时快速的printf
就足够了。
我经常使用这个构造:
#define DEBUG 1 #if DEBUG #if PROG1 #define DEBUGSTR(msg...) { printf("P1: "); printf( msg); } #else #define DEBUGSTR(msg...) { printf("P2: "); printf( msg); } #endif #else #define DEBUGSTR(msg...) ((void) 0) #endif
这样我可以在我的控制台中告诉哪个程序正在提供哪些错误消息…另外,我可以轻松搜索我的错误消息…
就个人而言,我不喜欢#defining只是表达的一部分……
它已经完成了。 我不推荐它。 没时间测试,但机制有点像这样:
#define printd_CAT(x) x ## x #ifndef DEBUG #define printd printd_CAT(/) #else #define printd printf #endif
如果您的编译器在编译器本身处理//注释(这不保证像ANSI保证有两个/ *注释的传递),这是有效的。
你可以利用if
。 例如,
#ifdef debug #define printd printf #else #define printd if (false) printf #endif
如果您设置像-O2
这样的优化标志,编译器将删除这些无法访问的代码。 这个方法对std::cout
也很有用。