为啥 C 预处理器不忽略它跳过的块中的无效指令?

Posted

技术标签:

【中文标题】为啥 C 预处理器不忽略它跳过的块中的无效指令?【英文标题】:Why doesn't the C preprocessor ignore invalid directives in blocks it skips?为什么 C 预处理器不忽略它跳过的块中的无效指令? 【发布时间】:2016-12-25 17:27:36 【问题描述】:

考虑以下代码:

#if 0
   #foobar
#endif

在这种情况下,预处理器不会抱怨#foobar 不是有效的预处理器指令。由于#if 0,它只是跳过了该块,并且代码编译得很好。

现在考虑以下代码:

#if 0
   #if 1
#endif

在这种情况下,预处理器突然抱怨缺少#endif 指令。这让我很困惑,因为它表明即使在#if 0 的情况下,预处理器似乎也没有完全忽略#if 0 块中的内容。似乎#if 指令仍在被解析,预处理器甚至会强制它们的正确性,即每个#if 都需要与#endif 匹配,即使在被跳过的块中也是如此。

以前,我的印象是使用#if 0 / #endif 封装一个块相当于使用/**/ 对其进行注释。但显然情况并非如此。

因此我的问题是:

    这种设计背后的基本原理是什么?为什么预处理器会强制执行正确匹配的 #if 指令,即使是在预处理器被明确告知要跳过的块中(使用 #if 0 等某些指令)?

    哪些指令确切#if 0 块中处理?如上例所示,预处理器不会抱怨像#foobar 这样的无效预处理器指令,但它会抱怨不匹配的#if 指令。那么哪些预处理器指令实际上是在#if 0 块中处理的?只有#if / #ifdef / #elif / #else / #endif 还是有更多的指令在#if 0 块中处理?

【问题讨论】:

因为预处理器不知道 which #if 缺少 #endif。缩进不告诉它!在第二个示例中,如果您缩进 #endif,错误消息会让您感到惊讶吗? 预处理器必须查看 #if/#endif 指令,即使在未采用的分支中,否则嵌套的 #if 不可能工作。跨度> 哦,对,当然有道理。很明显为什么它必须是这样的。好吧,我想让我们把它归咎于圣诞节:) 【参考方案1】:

只处理可以改变控制流的指令。其余的,如#foobar 被忽略1


1(引自:ISO/IEC 9899:201x 6.10.1 有条件包含 6) 按顺序检查每个指令的条件。如果它评估为假(零),则该组 它控制的被跳过:指令仅通过确定的名称来处理 该指令用于跟踪嵌套条件的级别;剩下的 指令的预处理标记被忽略,其他预处理标记也是如此 组

【讨论】:

以上是关于为啥 C 预处理器不忽略它跳过的块中的无效指令?的主要内容,如果未能解决你的问题,请参考以下文章

如何有效地处理类似于 Matlab 的 blkproc (blockproc) 函数的块中的 numpy 数组

C/C++中的预编译指令

如何忽略具有给定前缀的文件?

为啥在管道代码块中延迟扩展会失败?

如何在 <%=value%> 类型的块中强制执行赋值

nginx 配置详解是啥?