【问题标题】:Do preprocessors expand macros surrounded by quotation marks?预处理器会扩展用引号括起来的宏吗?
【发布时间】:2025-12-15 03:55:02
【问题描述】:

常见的预处理器(如 cpp 和 fpp)是否扩展由一对引号括起来的宏?

我尝试了以下代码同时使用cpp和fpp,似乎引号内的宏没有展开。但是,我在任何有关 cpp 或 fpp 的文档中都没有找到此规则。任何人都可以指导我查看一些文档,以便我可以确定这种行为吗?谢谢。

#define X Y
X
"X"
'X'

【问题讨论】:

标签: c unix fortran preprocessor


【解决方案1】:

常见的预处理器(如 cpp 和 fpp)是否扩展由 a 包围的宏 一对引号?

C 语言规范描述了符合 C 预处理器的行为。 C 的实际标准不是免费提供的,但您可以获得后期草稿的副本。例如,对于 C18,您可以参考 N2176。特别是,您应该查看第 5.1.1.2 和 6.10.3 节。特别相关的是第 6.10.3 节中的脚注 173:

因为,通过宏替换时间,所有字符常量和字符串 文字是预处理标记,而不是可能包含的序列 类似标识符的子序列(见 5.1.1.2,翻译阶段),它们 永远不会扫描宏名称或参数。

(在标准的早期版本中也出现了基本相同的文本。)

因此,C 的底线是 no,符合 C 的预处理器不会对字符串文字或字符常量的内容执行宏替换。


Fortran 的情况不太明确,因为 Fortran 语言规范没有定义预处理设施。语言本身内置了一个 include 语句,但 Fortran 从业者通常不会考虑使用它来涉及预处理。 Fortran 源代码很少依赖宏扩展或条件编译等预处理功能。

尽管如此,一些 Fortran 实现确实提供了预处理工具,有时可作为名为 fpp 的独立程序提供。有关详细信息,您需要查阅特定 fpp 的文档,但通常这些是 C 预处理器对 Fortran 语法的改编。因此,no,我不希望 Fortran 预处理器对字符文字的内容执行宏扩展。在这方面,我不知道有任何违背我期望的实现。

【讨论】:

  • 曾几何时,Fortran 确实指定了一个预处理器(但不是现在)。
  • 我已经使用 Fortran 很长时间了,@francescalus,据我所知,Fortran 66、Fortran 77、Fortran 90、Fortran 95、Fortran 2003、Fortran 2008 都没有, 或 Fortran 2018 定义了一个预处理器。我是否忽略了某些东西,还是您说“Fortran”时的意思与所有这些不同?
  • ISO/IEC 1539-3:1999.
  • 谢谢,@francescalus,它在我的雷达下飞行。然而,经过一番研究,我发现 ISO/IEC 1539-3:1999 指定的可选 Fortran 95 预处理器似乎只支持条件编译,不支持宏替换。因此,尽管它的存在是一个有趣的历史记录,但该预处理器与 OP 的问题无关。
  • 哦,是的,它丝毫不会影响您的回答。甚至“Fortran 语言规范没有定义预处理设施”,因为 Fortran 不再这样做。
【解决方案2】:

对于 C(不知道 Fortran,但可能相同):

处理器是否扩展用引号括起来的宏?

没有。

当宏的标识符是字符串文字 ("") 或字符常量 ('') 的一部分时,宏不会被扩展。然后宏标识符/名称成为字符串文字/字符常量的一部分。

"X" - 这是一个 字符串文字 字符 'X' + '\0'

'X' - 这是字母X字符常量

【讨论】:

  • 非常感谢您的回答和解释!
【解决方案3】:

另一种观点是:预处理器替换标记/标识符,它对此很有用。文字(无论是数字还是字符串)都不是标识符,用它来代替它是没有用的——而且风险很大。

另一个答案提到符合 C 的预处理器不应该替换文字字符串。为了更进一步,我尝试编译以下程序:

#define 12 13
#include <stdio.h>

main() {
  printf("%i\n", 12);
}

结果(gcc 版本 8.3.0,Debian 8.3.0-6)是:

test.c:1:9: error: macro names must be identifiers
 #define 12 13
         ^~

我认为这表明预处理器想要使用标识符。

【讨论】:

  • 非常感谢您的回答和解释!