正在运行从具有"约束违规的代码生成的二进制文件"实际上未定义的行为?

时间:2016-12-14 18:02:30

标签: c language-lawyer

参考:This question

上下文:return末尾的main()语句,没有表达式,例如

 return;

当我阅读标准时,它似乎是undefined behavior,所以我写了an answer

然而,another answer说,它不是UB。

我在哪里阅读或理解标准的语言错误?

注意:我已经看过this thread,但我不能总结。

4 个答案:

答案 0 :(得分:8)

让我们假设这个背景:

int main(void) {
    return;
}

和托管实施。

请注意,void main()不是严格禁止的(允许实施允许),return;main的定义中完全有效。

首先,这个return;显然违反了约束条件。它违反了N1570 6.8.6.4p1:

  

没有表达式的 return 语句只会出现在返回类型为 void 的函数中。

(这不是C90中的约束违规;在C99中已经改变了。)

该标准要求编译器为包含违反约束或语法规则的任何程序发出至少一个诊断。一旦完成,它就可以继续生成可执行文件(如果诊断是非致命的警告)。

目前尚不清楚具有约束违规的程序是否存在未定义行为的一般规则。标准没有明确说明。它定义了一个"约束"作为

  

限制,无论是句法还是语义,通过它来解释语言元素的阐述

我自己的解释是,如果违反约束,则没有有效的解释,因此行为未定义,但有些人不同意。我希望在未来的标准中看到明确的声明。

我认为C标准的措辞在这一点上确实含糊不清。

如果没有这样的一般规则,就不清楚行为是否未定义。在陈述此代码违反的约束之后,标准继续定义return语句的语义:

  

return 语句终止当前函数的执行   并将控制权返回给其来电者。

即使存在此约束违规,该描述仍然有意义。可以合理地假设,return;等同于达到结束},这相当于return 0;(这是一个main的特殊情况规则; N1570 5.1.2.2.3)。

另一方面,它并非100%清楚,描述是明确的。 return;相当于达到收盘}的论点特别薄弱。因此,即使在没有一般规则的情况下,也可以认为行为是由于遗漏而未定义的(没有对行为的定义)。

return;显然违反了约束,而在我看来如果实现产生可执行文件,则它具有未定义的行为。当然,也允许符合标准的编译器完全拒绝该程序;在这种情况下,它根本没有任何行为。

结论: 很多 更容易将return;更改为return 0;而不是回答这个问题。

我鼓励其他语言律师反驳这个答案。我在这里提出了足够的内部不一致的论点,认为它不应该太难。

答案 1 :(得分:1)

回答标题:

  

运行从具有“约束违规”的代码生成的二进制文件实际上是未定义的行为吗?

我说没有,因为标准中定义了未定义的行为,强调我的:

  

如果''应'或''不应''要求出现在之外   违反约束或运行时约束,行为未定义。   本国际标准中未明确的行为另有说​​明   通过“未定义的行为”或任何明确的遗漏   行为的定义。重点之间没有区别   这三个;他们都描述''未定义的行为''

     

§4/ 2

假设违反约束意味着违反“应该”或“不应该”要求 in 标记为“约束”的部分,并且没有另外表明违规导致UB。

根据上下文情况,我同意Keith Thompson的回答。

答案 2 :(得分:0)

标准没有定义包含约束违规的代码的行为。因此行为未定义。

说包含约束违规的代码是明确定义的,等于说可以忽略标准中的所有约束,这是荒谬的。

答案 3 :(得分:0)

作为具有约束违规的程序可能导致的真实场景 未定义的行为,考虑一个不擦除输出文件的构建系统 除非/直到有东西替换它们。当喂一个有效的程序 它创建一个具有特定名称的可执行文件,并在输入无效时 程序它保留旧文件未修改。由于用于生成剩余可执行文件的源文本可能与当前源文本无关,因此可执行文件的行为可能与当前源文件中的任何内容任意不同。

理想情况下,实现会尝试防止意外执行此类遗留代码,但如果C编译器只是较大构建系统的一小部分,则编译器可能无法控制此类问题,我怀疑作者标准的意思是说构建系统没有让编译器删除或使可执行文件无效(它可能一无所知)应该无法托管符合C的实现。