Dam*_*mon 23 c++ undefined-behavior language-lawyer
C++标准配备的用于定义一个惊人的数不清楚1种,其意味着与细微的差别或多或少相同的行为.读到这个答案后,我注意到"该程序格式错误;无需诊断"的措辞.
实现定义与未指定的行为的不同之处在于前一种情况下的实现必须清楚地记录它正在做什么(在后一种情况下,它不需要),两者都是格式良好的.未定义的行为与未指定的行为不同,因为程序是错误的(1.3.13).
否则它们都有一个共同点,就是标准不会对实现的内容做出任何假设或要求.除1.4/8之外,其中声明实现可能具有不会改变格式良好的程序的行为的扩展,但根据标准是不正确的,并且实现必须诊断使用这些,但之后可以继续编译和执行不正当的计划.
一个病态的程序否则只能定义为没有很好地形成(太棒了!).甲合式程序,在另一方面,被定义为一个附着在语法和诊断的语义规则.因此,这意味着错误的程序是打破语法或语义规则(或两者)的程序.换句话说,一个不正确的程序实际上根本不应该编译(如何以任何有意义的方式翻译例如具有错误语法的程序?).
我倾向于认为错误这个词也意味着编译器应该使用错误消息中止构建(毕竟,错误表明存在错误),但1.3.13中的"注意"部分明确允许不同的东西,包括默默地忽略问题(并且编译器显然不会因为UB 而破坏构建,大多数甚至不会默认警告).
人们可能会进一步认为错误和不正确的形式是相同的,但如果情况或该词应该是什么意思,那么标准就不会详细说明.
此外,1.4表示
符合要求的实施应[...]接受并正确执行格式良好的程序
和
如果程序包含违反不需要诊断的规则,则不要求对该程序进行实施.
换句话说,符合要求的实现必须接受格式良好的程序,但它也可能接受形式错误的程序,甚至没有警告.但是,如果程序因为使用扩展而格式不正确.
第二段建议任何与"无需诊断"相关的内容意味着规范中没有要求,这意味着它大部分等同于"未定义的行为",除非没有提到错误.
因此,使用"形成不良;无需诊断"等措辞背后的意图是什么?
"无诊断"的存在表明它与未定义的行为完全相同(或大部分相同?).此外,由于实现定义和未指定的行为被定义为格式良好,因此它必须是不同的.
另一方面,由于格式错误的程序会破坏语法/语义规则,因此它实际上不应该编译.但是,与"不需要诊断"相结合意味着允许编译器在没有警告的情况下以静默方式退出,并且之后您将无法找到可执行文件.
"形成不良;无需诊断"和"未定义行为"之间是否存在差异,或者这只是同一事物的复杂同义词?
Jam*_*nze 14
标准并不总是像我们希望的那样连贯,因为它是一个非常大的文档,由许多不同的人编写(实际上),尽管所有的校对确实发生了,但是不一致性会漏掉.在未定义的行为(以及一般的错误)的情况下,我认为还有一个额外的问题,对于大多数最基本的东西(指针等),C++标准从C启发.但C标准采取了这一点除非另有说明,否则所有错误都是未定义的行为,其中C++标准试图采用所有错误都需要诊断的观点,除非另有说明.(虽然他们仍然必须考虑标准省略指定行为的情况.)我认为这解释了措辞中的许多不一致.
在全球范围内,这种不一致是令人遗憾的,但总的来说,如果标准说某些东西是错误的或形成不良的,那么它需要诊断,除非标准说它没有,或者它是未定义的行为.在" 形成不良;无需诊断 "之类的情况下," 无需诊断 "非常重要,否则需要进行诊断.至于"形成不良;无需诊断"和"未定义行为"之间的区别,没有任何区别.第一种可能在代码不正确的情况下更频繁,第二种情况可能是运行时问题,但它不是系统性的.(一个定义规则的规范 - 显然是编译时间问题 - 以"然后行为未定义"结束.)
它应该是这样的:只要特定的程序运行不触发未定义的行为,未定义的东西不会引起问题.例如,空指针解除引用只会破坏您的特定程序运行时的日期(以其输入为特征:I/O,非确定性函数,如时钟查询等)实际执行它 - 但它会向后延伸,因此它可能会显示未定义甚至在技术上达到取消引用之前的行为.(这主要是为了允许我认为的代码重排.)
虽然格式错误的NDR是实现在翻译期间应该诊断的内容,但可能由于各种技术或理论限制而无法实现.例如,ODR要求实施收集实体的所有定义并进行比较; 但这是一个巨大的资源消耗.一些NDR的东西甚至在计算上是不可行的.当实现没有立即诊断出这些东西时,就会出现未定义的行为.
实际上,未定义的行为适用于一些非运行时条件的奇怪情况.一些奇怪的预处理器问题会触发未定义的行为.这些都很奇怪,因为它们在编译的程序中没有有意义的表示,因此不清楚导致它们执行的原因.
尽管如此,这种观点仍然可以为您提供合理的理由,说明为什么有两个术语.