C标准是否保证#error指令的诊断信息?

9
我有些困惑关于N1570 C11草案中5.1.1.3/1 Diagnostics子句的语义(强调是我的):

即使行为也被明确指定为未定义或实现定义,符合规范的实现必须生成至少一条诊断消息(以实现定义的方式标识),如果预处理翻译单元或翻译单元包含任何语法规则或约束的违反,则应生成至少一条诊断消息。 在其他情况下不需要生成诊断消息9

我理解这个意图是排除(非约束性的)未定义行为(因此没有缓冲区溢出等诊断),但是对于#error编译指令呢?就像在6.10.5/1 Error directive中所述:

形式为

# error pp-tokensopt new-line

的预处理指令会导致实现生成包括指定的预处理标记序列的诊断消息

这两个子句是否不相互排斥?
对于其他参考,请参见DR#176

4
我猜想意图是#error应该总是生成一条诊断消息,但这在前面的子句中没有提到。 - Drew McGowen
1
据我所知,Keith Thompson曾说过,错误指令是唯一需要实现产生诊断的地方。 - user3920237
1
“need not be produced”并不意味着“不能被生产”。 - Hans Passant
@remyabel:我认为这一点可以争议,因为“应该生成”(5.1.1.3/1)意味着“需要符合实现”,而这个子条款是规范性的。 - Grzegorz Szpetkowski
1
@GrzegorzSzpetkowski 精确地说,在这个上下文中,“shall”实际上意味着“必须”。 - kdopen
2个回答

4
作为委员会的成员之一,我们对这类问题的回答通常是以“仔细阅读标准…”这样的短语开始的,其实际意义比听起来要复杂。所用的语言非常具体。请考虑第一个从句。
“一个符合规范的实现应该在预处理转换单元或转换单元包含任何语法规则或约束违例(即使行为也明确指定为未定义或实现定义),产生至少一条诊断消息(以实现定义的方式标识)。不必在其他情况下生成诊断消息。”
该从句明确提到“任何语法规则或约束违例”。因此,良好形式的#error指令不触发该从句。因此,它不适用,而互斥无意义。
同时,请注意最后一句话,其中指出“不必生成”诊断信息。术语“不必”并不意味着“一定不能”。它只是表示实现可以选择是否针对其他情况(例如风格问题)发布诊断消息。但是,对于#error来说,整个从句都与其无关。
您的第二个引用简单地说明了对于良好形式的#error指令实现必须执行的内容。

1
它的意思是实现有选择是否发出诊断。但在#error的情况下,诊断消息始终是必需的(除非它在例如带有false条件的#if指令中,但这不是实现的问题)。我并不是暗示“不需要生成”意味着“不能生成”,而是“在其他情况下没有产生诊断消息的义务”。我希望我的观点很清楚。 - Grzegorz Szpetkowski
是的,你说得对。但是,正如我所说,这个句子是一个从属分句,适用于语法违规的情况。理解标准语可能会让人感到困惑。尝试使用一些通信标准 :) - kdopen
1
这个答案肯定是不正确的。 "诊断消息在其他情况下不需要生成" 的整个意义在于它适用于不违反任何语法规则或约束条件的程序。一个典型的例子可能是 int main(void) { 1 / 0; },对于这个例子,它指定不需要进行诊断。#error Hello / int main(void) { } 也没有违反任何语法规则或约束条件。 - user743382
1
“need not” 的确不意味着 “must not”。但它仍然与 “must” 或 “shall” 互斥。正如你所说,“need not” 意味着编译器在其他情况下有是否发出诊断的选项。而 #error 的规则是编译器没有这个选项。这肯定是矛盾的。 - Ben Voigt

4

C99比该DR建议的解决方案更进一步。他们不仅要求进行诊断,还要求将其视为错误。

4. 符合性

4. 如果 #error 预处理指令不是条件包含跳过组的一部分,则实现不得成功地转换预处理翻译单元。

现在,严格来说,也许你是对的,实现可以选择拒绝编译包含 #error 指令的程序,而不发出诊断,声称5.1.1.3允许它忽略 #error 的语义。然而,这样费尽心思地使自己在标准规定范围内变得无用的实现很容易就会规避任何要求诊断的尝试:实现可以简单地转储完整的预处理器输出(包括 #error 后面的任何内容),然后跟着“有一个错误在那里”。因此,标准是否要求诊断实际上并不重要。没有理由不这样做,标准也很少能够强制不愿意的实现者去做。


当一个C源文件成功翻译后,这意味着必须存在某个文件,可能需要进行额外处理,才能生成可运行的程序。标准是否对编译失败时宇宙的状态有任何规定?除非标准要求编译器在编译失败时确保不存在任何类似于预期输出文件的内容,否则我不确定强制性的失败会意味着什么。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接