假设IDE在Release构建中定义了宏NDEBUG
。是否可以使用以下预处理器指令在debug构建中打印调试信息,而不是使用marcoPRINT
在Release构建中打印?
#ifdef NDEBUG
#define PRINT /##/
#else
#define PRINT printf
#endif
否,因为在C的翻译阶段,用空格替换注释发生在宏替换之前。
C 2018 5.1.1.2 1规定了翻译中语法规则的优先顺序。第3阶段是:
源文件被分解为预处理标记和空白字符序列(包括注释(。源文件不应以部分预处理标记或部分注释结尾。每个注释都替换为一个空格字符…
第4阶段是:
执行预处理指令,扩展宏调用…
有趣的是,早期阶段可以被后期阶段调用,但这只发生在处理#include
指令时;第4阶段的规范继续:
…#include预处理指令导致命名的头文件或源文件从阶段1到阶段4进行递归处理…
此外,将/
与/
粘贴以生成//
具有未定义的行为,因为//
不是预处理令牌,而C 2018 6.10.3.3表示,使用##
运算符进行粘贴:
…如果结果不是有效的预处理令牌,则行为未定义…
(预处理令牌在C 2018 6.41中指定,相关类别为标点符号,包括字符和字符组合,如[
、]
、+
、++
、/
、+=
、/=
、>>=
等,但不包括//
。(
在调试构建而非非调试构建中实现打印目标的一种典型方法是定义一个类似函数的宏,该宏在非调试构建中将不被任何内容所取代:
#if defined NDEBUG
#define PRINT(...)
#else
#define PRINT(...) printf(__VA_ARGS__)
#endif