简体   繁体   English

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

[英]What is indeterminate behavior in C++ ? How is it different from undefined behavior?

What is the difference between an indeterminate behaviour and an undefined behaviour in C++? C ++中不确定行为和未定义行为之间有什么区别? Is this classification valid for C codes also? 此分类是否也适用于C代码?

The following remarks are based on the C standard, ISO-9899 , rather than the C++ one, but the meanings are fundamentally the same (see sections 3.4 and 4 of the C standard; see also the C++ standard, ISO-14882 , section 1.3; the latter document doesn't define 'unspecified value' as such, but does use that phrase later with the obvious meaning). 以下评论基于C标准ISO-9899 ,而不是C ++标准,但其含义基本相同(参见C标准的3.4和4节;另见C ++标准, ISO-14882,1.3节) ;后一个文档没有定义'未指定的值',但后来确实使用了该词组,具有明显的含义)。 The official standards documents are not free (indeed, they are expensive), but the links above are to the committee pages, and include free 'drafts' of the standard, which you can take to be essentially equivalent to the finalised standard text. 官方标准文件不是免费的(事实上,它们很昂贵),但上面的链接是委员会页面,并包括标准的免费“草稿”,您可以采取这些标准基本上等同于最终的标准文本。

The terms describe a ladder of vagueness. 这些术语描述了模糊的阶梯。

So, heading downwards.... 所以,向下走......

Most of the time, the standard defines what should happen in a particular case: if you write c=a+b and a and b are int , then c is their sum (modulo some details). 大多数情况下,标准定义了在特定情况下应该发生的事情:如果你写c=a+babint ,那么c就是它们的总和(以某些细节为模)。 This, of course, is the point of a standard. 当然,这是标准的要点。

Implementation-defined behaviour is where the standard lists two or more things which are allowed to happen in a particular case; 实现定义的行为是标准列出在特定情况下允许发生的两件或更多事情的地方; it doesn't prescribe which one is preferred, but does demand that the implementation (the actual compiler which parses the C) makes a choice between the alternatives, does that same thing consistently, and that the implementation must document the choice it makes . 它没有规定哪一个是首选,但确实要求实现(解析C的实际编译器)在备选方案之间作出选择,同样地做同样的事情,并且实现必须记录它做出的选择 For example, whether a single file can be opened by multiple processes is implementation-defined. 例如,是否可以通过多个进程打开单个文件是实现定义的。

Unspecified behaviour is where the standard lists a couple of alternatives, each of which is therefore conformant with the standard, but goes no further. 未指明的行为是标准列出几个备选方案的地方,因此每个备选方案都符合标准,但不再进一步。 An implementation must choose one of the alternatives to pick in a particular case, but doesn't have to do the same thing each time, and doesn't have to commit itself in documentation to which choice it will make. 实现必须选择其中一个替代方案来选择特定情况,但不必每次都做同样的事情,并且不必在文档中提交它将做出哪些选择。 For example, the padding bits in a struct are unspecified. 例如, struct中的填充位未指定。

Undefined behaviour is the most extreme case. 未定义的行为是最极端的情况。 Here, all bets are off. 所有的赌注都关闭了。 If the compiler, or the program it generates, runs into undefined behaviour , it can do anything: it can scramble memory, corrupt the stack, HCF or, in the standard extreme case, cause demons to fly out of your nose. 如果编译器或它生成的程序遇到未定义的行为 ,它可以做任何事情:它可以扰乱内存,破坏堆栈, HCF,或者在标准的极端情况下,导致恶魔飞出你的鼻子。 But mostly it'll just crash. 但大多数情况下它只会崩溃。 And all of these behaviours are conformant with the standard. 所有这些行为都符合标准。 For example, if a variable is declared both static int i; 例如,如果变量同时声明为static int i; and int i; int i; in the same scope, or if you write #include <'my file'.h> , the effect is undefined. 在相同的范围内,或者如果你写#include <'my file'.h> ,效果是不确定的。

There are analogous definitions for 'value'. “价值”有类似的定义。

An unspecified value is a valid value, but the standard doesn't say what it is. 未指定的值是有效值,但标准没有说明它是什么。 Thus the standard might say that a given function returns an unspecified value. 因此,标准可能会说给定函数返回未指定的值。 You can store that value and look at it if you want to, without causing an error, but it doesn't mean anything, and the function might return a different value next time, depending on the phase of the moon. 您可以存储该值并在需要时查看它,而不会导致错误,但这并不意味着什么,并且该函数可能会在下次返回不同的值,具体取决于月亮的相位。

An implementation-defined value is like implementation-defined behaviour. 实现定义的值类似于实现定义的行为。 Like unspecified , it's a valid value, but the implementation's documentation has to commit itself on what will be returned, and do the same thing each time. 就像未指定的那样 ,它是一个有效的值,但是实现的文档必须在将要返回的内容上提交,并且每次都执行相同的操作。

An indeterminate value even more unspecified than unspecified . 一个不确定的值未指定的更加未指定 It's either an unspecified value or a trap representation . 它可以是未指定的值或陷阱表示 A trap representation is standards-speak for some magic value which, if you try to assign it to anything, results in undefined behaviour. 陷阱表示是标准 - 代表一些神奇的价值,如果你试图将它分配给任何东西,会导致不确定的行为。 This wouldn't have to be an actual value; 这不一定是实际价值; probably the best way to think about it is "if C had exceptions, a trap representation would be an exception". 可能最好的思考方式是“如果C有异常,陷阱表示将是一个例外”。 For example, if you declare int i; 例如,如果您声明int i; in a block, without an initialisation, the initial value of the variable i is indeterminate , meaning that if you try to assign this to something else before initialising it, the behaviour is undefined, and the compiler is entitled to try the said demons-out-of-nose trick. 在一个块中,没有初始化,变量i的初始值是不确定的 ,这意味着如果在初始化之前尝试将其分配给其他东西,则行为是未定义的,并且编译器有权尝试所述的恶魔鼻子戏法。 Of course, in most cases, the compiler will do something less dramatic/fun, like initialise it to 0 or some other random valid value, but no matter what it does, you're not entitled to object. 当然,在大多数情况下,编译器会做一些不那么戏剧性/有趣的事情,比如将其初始化为0或其他一些随机有效值,但无论它做什么,你都无权反对。

The point of all this imprecision is to give maximal freedom to compiler writers. 所有这些不精确的关键是为编译器编写者提供最大的自由度。 That's nice for compiler writers (and is one of the reasons it's reasonably easy to get a C compiler running on such a huge range of platforms), but it does make things rather more interesting than fun for the poor users. 这对于编译器编写者来说很好(这也是让C编译器在如此大范围的平台上运行相当容易的原因之一),但它确实让穷人用户感到有趣而不是有趣。

Edit 1 : to clarify indeterminate values. 编辑1 :澄清不确定的值。

Edit 2 : to include a link to the C++ standard, and note that the committee drafts are essentially equivalent to the final standard, but free. 编辑2 :包含C ++标准的链接,并注意委员会草案基本上等同于最终标准,但是免费。

I think the standard mentions undefined behaviour and indeterminate value . 我认为标准提到了未定义的行为和不确定的价值 So one is about the behaviour and another about values. 所以一个是关于行为而另一个关于价值观。

These two are somewhat orthogonal, for example, the behaviour can still be well defined in the presence of indeterminate values. 这两者在某种程度上是正交的,例如,在存在不确定值的情况下仍然可以很好地定义行为。

EDIT 1: The last drafts of C11 and C++11 are available online here: C11 draft N1570 and C++11 draft n3242 if you don't have a copy of the final standards and wonderful what they look like. 编辑1: C11和C ++ 11的最后草稿可在线获取: C11草案N1570C ++ 11草案n3242如果您没有最终标准的副本并且它们看起来很棒。 (Other adjustments to text appearance and some wording/grammar edits have been done.) (已经完成了对文本外观和一些措辞/语法编辑的其他调整。)

EDIT 2: Fixed all occurrences of "behaviour" to be "behavior" to match the standard. 编辑2:修正所有出现的“行为”为“行为”以匹配标准。

Searching the C++11 and C11 standards there are no matches for indeterminate rule or undefined rule . 搜索C ++ 11和C11标准时, 不确定规则未定义规则没有匹配项。 There are terms like indeterminate value , indeterminately sequenced , indeterminate uninitialized , etc. 存在诸如不确定值不确定序列不确定未初始化等术语。

If talk of traps and exceptions seems weird in Norman Gray's answer, know that those terms do reflect the relevant definitions in Section 3 in the C11 standard . 如果在Norman Gray的答案中谈论陷阱和异常似乎很奇怪,请知道这些术语确实反映了C11标准 第3节中的相关定义。

C++ relies on C's definitions. C ++依赖于C的定义。 Many useful definitions concerning types of behaviour can be found in C11's Section 3 (in C11). 关于行为类型的许多有用定义可以在C11的第3节(C11中)中找到。 For example, indeterminate value is defined in 3.19.2. 例如, 不确定值在3.19.2中定义。 Do take note that C11's Section 2 (Normative References) provides other sources for additional terminology interpretation and Section 4 defines when cases such as undefined behavior occur as a result of not complying with the standard. 请注意,C11的第2节(规范性引用文件)提供了其他术语解释的其他来源,第4节定义了由于不遵守标准而发生未定义行为等情况。

C11's section 3.4 defines behavior , 3.4.1 defines implementation-defined behavior , 3.4.2 defines locale-specific behavior , 3.4.3 defines undefined behavior , 3.4.4 defines unspecified behavior . C11的3.4节定义了行为 ,3.4.1定义了实现定义的行为 ,3.4.2定义了特定于语言环境的行为 ,3.4.3定义了未定义的行为 ,3.4.4定义了未指定的行为 For value (Section 3.19), there are implementation-defined value , indeterminate value , and unspecified value . 对于 (第3.19节),有实现定义的值不确定的值未指定的值

Loosely speaking, the term indeterminate refers to an unspecified/unknown state that by itself doesn't result in undefined behavior . 简而言之,术语“ 不确定”是指未指定/未知状态 ,其本身不会导致未定义的行为 For example, this C++ code involves an indeterminate value: { int x = x; 例如,这个C ++代码涉及一个不确定的值:{int x = x; }. }。 (This is actually an example in the C++11 standard.) Here x is defined to be an integer first but at that point it does not have a well-defined value --then it is initialized to whatever (indeterminate/unknown) value it has! (这实际上是C ++ 11标准中的一个例子。)这里x被定义为第一个整数,但此时它没有明确定义的值 - 然后它被初始化为任何(不确定/未知)它有价值!

The well-known term undefined behavior is defined in 3.4.3 in C11 and refers to any situation of a 众所周知的术语未定义行为在C11中的3.4.3中定义,并且指的是a的任何情况

nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements 不可移植或错误的程序构造或错误数据,本国际标准不对此要求

In other words undefined behavior is some error (in logic or state) and whatever happens next is unknown! 换句话说, 未定义的行为是一些错误(在逻辑或状态中),接下来发生的任何事情都是未知的! So one could make an undefined [behavior] rule that states: avoid undefined behavior when writing C/C++ code! 因此,可以制定一个未定义的[行为]规则 ,指出:在编写C / C ++代码时避免未定义的行为! :-) :-)

An indeterminate [behavior] rule would be to state: avoid writing indeterminate code unless it is needed and it does not affect program correctness or portability. 不确定的[行为]规则将指出:避免编写不确定的代码, 除非需要它并且它不会影响程序的正确性或可移植性。 So unlike undefined behavior, indeterminate behavior does not necessarily imply that code/data is erroneous, however, its subsequent use may or may not be erroneous --so care is required to ensure program correctness is maintained. 因此,与未定义的行为不同,不确定的行为并不一定意味着代码/数据是错误的,但是, 其后续使用可能会或可能不会是错误的 -因此需要注意确保维持程序的正确性。

Other terms like indeterminately sequenced are in the body text (eg, C11 5.1.2.3 para 3; C++11, section 1.9 para. 13; ie, in [intro.executation]). 其他术语如不确定序列在正文中(例如,C11 5.1.2.3第3段; C ++ 11,第1.9节第13段;即[intro.executation])。 (As you might guess, it refers an unspecified order of operational steps.) (正如您可能猜到的,它指的是未指定的操作步骤顺序。)

IMO if one is interested in all of these nuances, acquiring both the C++11 and C11 standards is a must. IMO如果对所有这些细微差别感兴趣,那么获得C ++ 11和C11标准是必须的。 This will permit one to explore to the desired level-of-detail needed with definitions, etc. If you don't have such the links provided herein will help you explore such with the last published draft C11 and C++11 standards. 这将允许人们通过定义等探索所需的详细程度。如果您没有这样的链接,将帮助您使用上次发布的C11和C ++ 11标准草案进行探索。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM