未定义的行为和格式错误之间的区别,不需要诊断消息

Difference between Undefined Behavior and Ill-formed, no diagnostic message required

本文关键字:区别 不需要 诊断 消息 之间 错误 格式 未定义      更新时间:2023-10-16

C++标准为不清楚的1行为提供了数量惊人的定义,这意味着或多或少相同,但有细微的差异。读到这个答案,我注意到"程序格式错误;不需要诊断">

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

格式不正确的程序在其他方面仅被定义为格式不正确(很棒!)。另一方面,格式良好的程序被定义为遵守语法和可诊断语义规则的程序。因此,这意味着一个格式错误的程序是一个破坏语法或语义规则(或两者兼有)的程序。换句话说,一个格式错误的程序实际上根本不应该编译(如何以任何有意义的方式翻译例如语法错误的程序?)。

我倾向于认为,单词errored也意味着编译器应该用错误消息中止构建(毕竟,error表明存在错误),但1.3.13中的"注意"部分明确允许不同的内容,包括默默地忽略问题(编译器显然不会因为UB而破坏构建,大多数编译器甚至默认情况下不会发出警告)。

人们可能会进一步认为,错误和格式错误是相同的,但如果是这样的话,或者这个词应该是什么意思,标准并没有详细说明。

此外,1.4指出

一个合格的实现应该[…]接受并正确执行一个格式良好的程序

如果程序违反了不需要诊断的规则,则[…]对该程序的实现没有要求。

换句话说,一个合格的实现必须接受一个格式良好的程序,但它也可能接受一个不正确的程序,甚至没有警告。除非程序格式不正确,因为它使用了扩展名。

第二段指出,任何与"无需诊断"结合的内容都意味着规范中没有要求,这意味着它主要等同于"未定义的行为",除非没有提到错误

因此,使用"格式错误;无需诊断">这样的措辞背后的意图是什么?

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

另一方面,由于格式错误的程序破坏了语法/语义规则,因此实际上不应该进行编译。然而,这与"无需诊断"一起意味着编译器将被允许在没有太多警告的情况下静默退出,并且之后您将无法找到可执行文件。

"格式错误;不需要诊断"answers"未定义的行为"之间有区别吗?还是这只是同一事物的复杂同义词?


1缺乏更好的行为集合措辞

标准并不总是像我们希望的那样连贯,因为这是一份很大的文件,(实际上)是用数字写的不同的人,尽管有所有的证据如果确实发生了,不一致就会溜走。假使未定义的行为(以及一般的错误),我认为对于大多数最基本的事情来说,这是一个额外的问题(指针等),C++标准的灵感来自CC标准认为所有错误都是未定义的行为,除非另有说明,其中作为C++标准尝试采取所有错误都需要的观点诊断,除非另有说明。(尽管他们仍然必须考虑到标准省略指定的情况行为。)我认为这占了很多措辞不一致。

在全球范围内,这种不一致令人遗憾,但总的来说,如果这个标准说有些东西是错误的,那么它需要诊断,除非标准规定没有,或者这是未定义的行为。在类似">格式错误;无需诊断",">no diagnosticrequired"很重要,因为否则,它将需要诊断。至于"不正规;否"之间的区别需要诊断"answers"未定义的行为",没有任何。第一种可能在代码不正确,第二个是运行时问题,但不是成体系的(一个定义的规范rule—显然是编译时的问题—以"then"结尾行为未定义"。)

它应该是:只要程序的特定运行没有触发未定义的行为,未定义的事情就不会引起问题。例如,当你运行的特定程序(以其输入:I/O、时钟查询等非确定性函数为特征)实际执行它时,空指针取消引用只会破坏你的一天,但它会向后延伸,因此即使在技术上达到取消引用之前,它也可能表现出未定义的行为。(我认为这主要是为了允许重新排列代码。)

而格式错误的NDR是实现在翻译过程中应该诊断的东西,但由于各种技术或理论限制,可能无法诊断。例如,网上解决将要求执行机构收集一个实体的所有定义并加以比较;但这是一个巨大的资源消耗。有些NDR的东西在计算上甚至是不可行的。当实现没有立即诊断出这些东西时,就会出现未定义的行为。

在实践中,未定义的行为适用于一些不是运行时条件的奇怪情况。一些奇怪的预处理器问题会触发未定义的行为。这些很奇怪,因为它们在编译的程序中没有有意义的表示,所以不清楚是什么导致它们执行。

尽管如此,这种观点仍然让你对为什么有两个术语有一个合理的想法。

cppreference现在似乎有一个非常有用的摘要:

"不需要诊断";表示某些措辞不规范根据语言规则,但编译器不需要发布任何诊断或错误消息。通常,原因是检测到这些情况会导致编译时间过长时间。

如果执行这样的程序,则行为是未定义的。

如果任何格式错误,而不是,则无需诊断,则必须产生编译错误。