为什么 C 预处理器是未定义行为的主体?

Pav*_*kin 4 c undefined-behavior language-lawyer c-preprocessor c11

我可以这么理解:

  • UB 的起源之一是性能提高(例如,通过删除从未执行的代码,例如if (i+1 < i) { /* never_executed_code */ };UPD:ifi是有符号整数)。
  • UB可以在编译时触发,因为C没有明确区分编译时和运行时。“整个语言基于“抽象机器”(链接)的(相当无用的)概念。

但是,我还不明白为什么 C 预处理器是未定义行为的主题?众所周知,预处理指令是在编译时执行的。

考虑 C11,6.10.3.3 ## 运算符,3:

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

为什么不把它作为一个约束呢?例如:

结果应是有效的预处理令牌。

同样的问题也适用于 6.10 预处理指令中的所有其他“行为未定义”。

Kam*_*Cuk 5

为什么 C 预处理器是未定义行为的主体?

当C标准创建时,有一些现有的C预处理器,并且在标准化委员会成员的脑海中也有一些想象的理想C预处理器。

因此存在这些灰色区域,委员会成员不完全确定他们想要做什么和/或现有的 C 预处理器实现在行为上彼此不同。

因此,这些情况不是定义的行为。因为 C 委员会成员并不完全确定行为实际上应该是什么。所以对于应该是什么没有要求。

UB的起源之一

是的,其中之一

UB 的存在可能是为了简化该语言的实现。例如,在预处理器的情况下,预处理器编写者不必关心当无效的预处理器标记是 的结果时会发生什么##

或者 UB 的存在可能是为了协调具有不同行为的现有实现或作为扩展点。因此,在 UB 情况下出现段错误的预处理器、在 UB 情况下接受并工作的预处理器以及在 UB 情况下格式化硬盘驱动器的预处理器,所有这些都可以符合标准(但我不想在这方面工作)格式化您的驱动器的一个)。

  • @pmor:编译器可以指定在标准没有规定的情况下它们的行为方式。如果编译器的设计者希望它以某种方式处理特定的构造,则该编译器的测试套件应该确认该行为。如果编译器的行为不符合预期,则表明某处可能存在错误,无论标准是否对此类行为进行了说明。 (3认同)
  • @pmor:对于“#include \`./woozle\”将执行名为“woozle”的程序并表现得好像其输出已插入源文件中的编译器,标准应该怎么说?不难想象这样的功能是有用的,但是标准无法说明在这样的编译器上编译任意源文本可能产生的后果。 (2认同)