提问者:小点点

什么是 C 中的不确定行为?它与未定义的行为有何不同?


在C语言中,不确定的行为和未定义的行为有什么区别?此分类是否也适用于 C 代码?


共3个答案

匿名用户

以下注释基于C标准ISO-9899,而不是C标准,但含义基本相同(参见C标准的第3.4和4节;另见C标准,ISO-14882,第1.3节;后一个文档没有定义“未指定的值”,但稍后确实使用该短语具有明显的含义)。官方标准文件不是免费的(事实上,它们很昂贵),但上面的链接是指向委员会页面的,包括标准的免费“草案”,你可以认为它基本上等同于最终的标准文本。

这些术语描述了模糊的阶梯。

所以,向下走...

大多数时候,标准定义了在特定情况下应该发生的情况:如果你写 c=a b 并且 abint,那么 c 就是它们的总和(模化一些细节)。当然,这是标准的重点。

实现定义的行为是标准列出了在特定情况下允许发生的两件或多件事;它没有规定哪一个是首选的,但确实要求实现(解析 C 的实际编译器)在替代方案之间进行选择,始终如一地做同样的事情,并且实现必须记录它所做的选择。例如,单个文件是否可以由多个进程打开是实现定义的。

未指定的行为是标准列出几个替代方案的地方,因此每个替代方案都符合标准,但没有进一步。实现必须选择在特定情况下选择的替代方案之一,但不必每次都做同样的事情,也不必在文档中promise它将做出哪个选择。例如,未指定结构中的填充位。

未定义的行为是最极端的情况。在这里,所有的赌注都关闭了。如果编译器或其生成的程序遇到未定义的行为,它可以做任何事情:它可以扰乱内存,破坏堆栈,HCF,或者在标准的极端情况下,导致恶魔从你的鼻子里飞出来。但大多数情况下,它只会崩溃。所有这些行为都符合标准。例如,如果一个变量在同一作用域中同时声明了静态 int i;int i,或者如果您编写了 #include

“价值”也有类似的定义。

未指定的值是有效值,但标准没有说明它是什么。因此,标准可能会说给定的函数返回一个未指定的值。您可以存储该值并根据需要查看它,而不会引起错误,但这没有任何意义,并且该函数下次可能会返回不同的值,具体取决于月相。

实现定义的值类似于实现定义的行为。与未指定一样,它是一个有效值,但实现的文档必须提交自己将返回的内容,并且每次都执行相同的操作。

不确定的值甚至比未指定更未指定。它要么是未指定的值,要么是陷阱表示形式。陷阱表示是某种魔术值的标准,如果你试图将其分配给任何东西,会导致未定义的行为。这不一定是实际值;也许最好的思考方式是“如果 C 有例外,陷阱表示就是例外”。例如,如果你在一个块中声明int i;在没有初始化的情况下,变量i的初始值是不确定的,这意味着如果你尝试赋值在初始化它之前,这是其他东西,行为是未定义的,编译器有权尝试所说的恶魔出鼻子的技巧。当然,在大多数情况下,编译器会做一些不那么戏剧性/有趣的事情,比如将其初始化为 0 或其他一些随机的有效值,但无论它做什么,你都无权反对。

所有这些不精确之处的重点是给编译器编写者最大的自由度。这对编译器编写者来说很好(也是让 C 编译器在如此广泛的平台上运行相当容易的原因之一),但它确实让事情变得有趣而不是有趣对于可怜的用户来说。

编辑 1:澄清不确定的值。

编辑2:包括C标准的链接,并注意委员会草案基本上等同于最终标准,但是免费的。

匿名用户

我认为该标准提到了未定义的行为和不确定的价值。所以一个是关于行为的,另一个是关于价值观的。

这两者在某种程度上是正交的,例如,在存在不确定值的情况下,行为仍然可以很好地定义。

匿名用户

编辑1:C11和C 11的最后草案可在此处在线获得:C11草案N1570和C 11草案N3242,如果您没有最终标准的副本,并且它们的外观很棒。(对文本外观进行了其他调整,并对一些措辞/语法进行了编辑。

编辑 2:将所有出现的“行为”修复为“行为”以符合标准。

搜索 C 11 和 C11 标准,不确定规则或未定义规则没有匹配项。有不确定值、不确定排序、不确定未初始化等术语。

如果在Norman Gray的回答中谈论陷阱和例外似乎很奇怪,请知道这些术语确实反映了C11标准第3节中的相关定义。

C 依赖于 C 的定义。许多关于行为类型的有用定义可以在C11的第3节(C11中)中找到。例如,不确定值在 3.19.2 中定义。请注意,C11的第2节(规范性参考文献)为其他术语解释提供了其他来源,第4节定义了何时由于不遵守标准而发生未定义行为等情况。

C11 的第 3.4 节定义了行为,3.4.1 定义了实现定义的行为,3.4.2 定义了特定于区域设置的行为,3.4.3 定义了未定义的行为,3.4.4 定义了未指定的行为。对于值(第 3.19 节),有实现定义的值、不确定的值和未指定的值。

粗略地说,术语不确定是指未指定/未知的状态,其本身不会导致未定义的行为。例如,此 C 代码涉及一个不确定的值:{ int x = x; }。(这实际上是 C 11 标准中的一个例子。这里 x 首先被定义为一个整数,但在这一点上它没有一个明确定义的值 - 然后它被初始化为它拥有的任何(不确定/未知)值!

众所周知的术语未定义行为在 C11 的 3.4.3 中定义,指的是

不可移植或错误的程序构造或错误数据,本标准对此没有要求

换句话说,未定义的行为是一些错误(在逻辑或状态中),接下来发生的任何事情都是未知的!因此,可以制定一个未定义的[行为]规则,声明:在编写C / C代码时避免未定义的行为!:-)

不确定的[行为]规则是声明:避免编写不确定的代码,除非需要并且不影响程序的正确性或可移植性。因此,与未定义的行为不同,不确定的行为并不一定意味着代码/数据是错误的,但是,其后续使用可能是错误的,也可能不是错误的 - 因此需要注意确保程序的正确性得到维护。

其他术语,如不确定顺序,在正文中(例如,C11 5.1.2.3 第3段;C 11,第1.9节第13段;即,在[介绍.执行]中)。(正如您可能猜到的那样,它指的是未指定的操作步骤顺序。

IMO 如果对所有这些细微差别感兴趣,则必须同时获得 C 11 和 C11 标准。这将允许人们探索定义等所需的详细程度。如果您没有此类链接,此处提供的链接将帮助您探索最新发布的 C11 和 C 11 标准草案。