宏定义中可以用“/##/”创建注释吗?

sta*_*er6 1 c c-preprocessor

假设IDENDEBUG在Release构建中定义了宏。是否可以使用以下预处理器指令在调试版本中打印调试信息,但不能通过使用 marco 在发布版本中打印调试信息PRINT?

#ifdef NDEBUG
#define PRINT /##/
#else
#define PRINT printf
#endif
Run Code Online (Sandbox Code Playgroud)

Eri*_*hil 7

否,因为在 C\xe2\x80\x99s 翻译阶段中,用空格替换注释发生在宏替换之前。

\n

C 2018 5.1.1.2 1 指定翻译中语法规则的优先级。第三阶段是:

\n
\n

源文件被分解为预处理标记和空白字符序列(包括注释)。源文件不应以部分预处理标记或部分注释结尾。每个注释都替换为一个空格字符\xe2\x80\xa6

\n
\n

第四阶段是:

\n
\n

执行预处理指令,展开宏调用\xe2\x80\xa6

\n
\n

有趣的是,早期阶段可以被后期阶段调用,但这仅发生在处理#include指令中;第 4 阶段的规范继续:

\n
\n

\xe2\x80\xa6 #include 预处理指令会导致指定的头文件或源文件从阶段 1 到阶段 4 递归地进行处理\xe2\x80\xa6

\n
\n

此外,粘贴/到/产生//具有未定义的行为,因为//不是预处理标记,并且 C 2018 6.10.3 3 说,使用##运算符粘贴:

\n
\n

\xe2\x80\xa6 如果结果不是有效的预处理标记,则行为未定义\xe2\x80\xa6

\n
\n

(预处理标记在 C 2018 6.4 1 中指定,相关类别为标点符号,其中包括[, ], +, , ++, /, +=, /=,等字符和字符组合>>=,但不包括//。)

\n

实现在调试版本中打印但不在非调试版本中打印的目标的典型方法是定义一个类似函数的宏,该宏在非调试版本中不被任何内容替换:

\n
#if defined NDEBUG\n    #define PRINT(...)\n#else\n    #define PRINT(...) printf(__VA_ARGS__)\n#endif\n
Run Code Online (Sandbox Code Playgroud)\n