未定义行为与错误形成之间的区别,无需诊断消息

Dam*_*mon 23 c++ undefined-behavior language-lawyer

C++标准配备的用于定义一个惊人的数不清楚1种,其意味着与细微的差别或多或少相同的行为.读到这个答案后,我注意到"该程序格式错误;无需诊断"的措辞.

实现定义未指定的行为的不同之处在于前一种情况下的实现必须清楚地记录它正在做什么(在后一种情况下,它不需要),两者都是格式良好的.未定义的行为与未指定的行为不同,因为程序是错误的(1.3.13).
否则它们都有一个共同点,就是标准不会对实现的内容做出任何假设或要求.除1.4/8之外,其中声明实现可能具有不会改变格式良好的程序的行为的扩展,但根据标准是不正确的,并且实现必须诊断使用这些,但之后可以继续编译和执行不正当的计划.

一个病态的程序否则只能定义为没有很好地形成(太棒了!).甲合式程序,在另一方面,被定义为一个附着在语法和诊断的语义规则.因此,这意味着错误的程序是打破语法或语义规则(或两者)的程序.换句话说,一个不正确的程序实际上根本不应该编译(如何以任何有意义的方式翻译例如具有错误语法的程序?).

我倾向于认为错误这个词也意味着编译器应该使用错误消息中止构建(毕竟,错误表明存在错误),但1.3.13中的"注意"部分明确允许不同的东西,包括默默地忽略问题(并且编译器显然不会因为UB 破坏构建,大多数甚至不会默认警告).

人们可能会进一步认为错误和不正确的形式是相同的,但如果情况或该词应该是什么意思,那么标准就不会详细说明.

此外,1.4表示

符合要求的实施应[...]接受并正确执行格式良好的程序

如果程序包含违反不需要诊断的规则,则不要求对该程序进行实施.

换句话说,符合要求的实现必须接受格式良好的程序,但它也可能接受形式错误的程序,甚至没有警告.但是,如果程序因为使用扩展而格式不正确.

第二段建议任何与"无需诊断"相关的内容意味着规范中没有要求,这意味着它大部分等同于"未定义的行为",除非没有提到错误.

因此,使用"形成不良;无需诊断"等措辞背后的意图是什么?

"无诊断"的存在表明它与未定义的行为完全相同(或大部分相同?).此外,由于实现定义未指定的行为被定义为格式良好,因此它必须是不同的.

另一方面,由于格式错误的程序会破坏语法/语义规则,因此它实际上不应该编译.但是,与"不需要诊断"相结合意味着允许编译器在没有警告的情况下以静默方式退出,并且之后您将无法找到可执行文件.

"形成不良;无需诊断"和"未定义行为"之间是否存在差异,或者这只是同一事物的复杂同义词?


1对行为集体缺乏更好的措辞

Jam*_*nze 14

标准并不总是像我们希望的那样连贯,因为它是一个非常大的文档,由许多不同的人编写(实际上),尽管所有的校对确实发生了,但是不一致性会漏掉.在未定义的行为(以及一般的错误)的情况下,我认为还有一个额外的问题,对于大多数最基本的东西(指针等),C++标准从C启发.但C标准采取了这一点除非另有说明,否则所有错误都是未定义的行为,其中C++标准试图采用所有错误都需要诊断的观点,除非另有说明.(虽然他们仍然必须考虑标准省略指定行为的情况.)我认为这解释了措辞中的许多不一致.

在全球范围内,这种不一致是令人遗憾的,但总的来说,如果标准说某些东西是错误的或形成不良的,那么它需要诊断,除非标准说它没有,或者它是未定义的行为.在" 形成不良;无需诊断 "之类的情况下," 无需诊断 "非常重要,否则需要进行诊断.至于"形成不良;无需诊断"和"未定义行为"之间的区别,没有任何区别.第一种可能在代码不正确的情况下更频繁,第二种情况可能是运行时问题,但它不是系统性的.(一个定义规则的规范 - 显然是编译时间问题 - 以"然后行为未定义"结束.)

  • @vonbrand不符合C++标准.没有什么能将"未定义的行为"限制为运行时.我知道:"行为"一词表示运行时.但是该标准使用了自己的定义,并且在其定义的上下文中,唯一的区别是"形式错误"可能需要诊断 - 事实上,除非另有说明,否则它确实需要诊断 - 并且未定义的行为不会不需要一个. (6认同)
  • 它们是有区别的."生成形成"意味着*程序*编写得很糟糕,"未定义行为"意味着在*运行时*可能会发生奇怪的事情. (4认同)
  • @JamesKanze:这是我对标准的__reading__,尽管是用一些非正式的语言。N3337 1.3.25 表示 UB 仅适用于格式良好的程序,而 1.3.26 则表示违反 ODR 并非格式良好。1.4 区分NDR和UB。我找不到任何明确 UB 的“格式错误,无需诊断”的示例。尽管您对定义充满信心,但我认为该标准在 NDR 和 UB 之间保持了明确的区别,但未能定义这种区别。 (3认同)
  • @ david.pfx"肯定x表示y"在处理标准(或任何标准)时不是你能说的.该标准非常明确地定义了它使用的术语.特别是,存在明确的"形成不良,无需诊断"的情况,这些情况是未定义的行为.并且违反一个定义规则(包括缺少定义)是未定义的行为,即使大多数实现在转换(在本例中为链接)时检测到它的至少一些实例. (2认同)
  • 我可以看到,产生未定义行为的构造与格式不正确的构造之间的唯一显着差异是,符合标准的编译器可以默认行为指定并记录其认为适合代表未定义行为的构造的任何有用含义,但是符合标准的编译器可能无法干净地编译标准状态不正确的构造(它可能允许程序运行,但是在使用默认设置时必须发出诊断信息)。也许“格式错误+ NDR”意味着不允许编译器对结构进行“记录”。 (2认同)

Seb*_*edl 8

它应该是这样的:只要特定的程序运行不触发未定义的行为,未定义的东西不会引起问题.例如,空指针解除引用只会破坏您的特定程序运行时的日期(以其输入为特征:I/O,非确定性函数,如时钟查询等)实际执行它 - 但它会向后延伸,因此它可能会显示未定义甚至在技术上达到取消引用之前的行为.(这主要是为了允许我认为的代码重排.)

虽然格式错误的NDR是实现在翻译期间应该诊断的内容,但可能由于各种技术或理论限制而无法实现.例如,ODR要求实施收集实体的所有定义并进行比较; 但这是一个巨大的资源消耗.一些NDR的东西甚至在计算上是不可行的.当实现没有立即诊断出这些东西时,就会出现未定义的行为.

实际上,未定义的行为适用于一些非运行时条件的奇怪情况.一些奇怪的预处理器问题会触发未定义的行为.这些都很奇怪,因为它们在编译的程序中没有有意义的表示,因此不清楚导致它们执行的原因.

尽管如此,这种观点仍然可以为您提供合理的理由,说明为什么有两个术语.