未指定的,不确定的,对于C实现定义的行为WIKI [英] Unspecified, undefined and implementation defined behavior WIKI for C

查看:446
本文介绍了未指定的,不确定的,对于C实现定义的行为WIKI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

虽然有丰富的关于SO这个问题的联系,我觉得有东西丢失:在什么明确的行为之间的区别(USB)通俗的语言解释清楚,<强>未定义行为(UB)和实现定义(IDB)与任何用例和示例的详细,但很容易解释。

Although there is plentiful of links about this subject on SO, I think that there is something missing: a clear explanation in plain language of what are the differences between unspecified behavior (UsB), undefined behaviour (UB) and implementation-defined behavior (IDB) with detailed but easy explanation of any use-case and example.

注意:我做了的 USB 的缩写,为在这个WIKI紧凑的缘故,但不希望看到它在其他地方使用

Note: I made the UsB acronym up for sake of compactness in this WIKI, but don't expect to see it used elsewhere.

我知道这可能看起来其他职位的副本(它更接近是<一个一个href=\"http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior?rq=1\">this),但之前,任何人都标志着其视为重复,请考虑是什么我已经发现了所有材料的问题(我要做一个社区维基出了这后):

I know this may seem a duplicate of other posts (the one it comes closer is this), but before anyone marks this as a duplicate, please consider what are the problems with all the material I already found (and I'm going to make a community WIKI out of this post):


  • 有太多散落的例子。例子是不差的,当然,但有时人们无法找到非常适合自己手头问题的例子,所以他们可能会产生混淆(特别是新手)。

  • Too many scattered examples. Examples are not bad, of course, but sometimes one cannot find an example that nicely fits his problem at hand, so they may be confusing (especially for newbies).

例如往往只code。与一些解释。在这样微妙的问题,尤其是对(相对)新手,更自上而下的方法可能会更好:首先明确的,具有一种抽象的简单的解释(但不是墨守成规)的描述,的然后的一些简单的例子与他们为什么引发一些行为的解释

Examples are often only code with few explanations. On such delicate matters, especially for (relative) newbies, a more top-down approach could be better: first a clear, simple explanation with an abstract (but not legalistic) description, then some simple examples with explanations on why they trigger some behavior.

有些帖子经常运动的C和C ++的例子组合。 C和C ++有时并不在他们认为什么USB,UB和美洲开发银行,这样的例子可以误导人两种语言不精通协议。

Some posts often sport a mix of C and C++ examples. C and C++ sometimes are not in agreement of what they deem UsB, UB and IDB, so an example can be misleading for someone not proficient in both languages.

在的USB定义,UB和IDB给定,通常是标准,有时可能不清楚或者太难以消化的新手一个简单的引用。

When a definition of UsB, UB, and IDB is given, usually it is a plain citation of the standards, which sometimes may be unclear or too difficult to digest for newbies.

有时标准的引用是局部的。很多帖子引用仅适用于那些手头的问题,这是很好的有用部分的标准,但缺乏通用性。另外的标准常常引证不伴随任何解释(坏的初学者)。

Sometimes the citation of the standards are partial. Many posts cite the standard only for the parts that are useful for the problem at hand, which is good, but lacks generality. Moreover citation of the standards often is not accompanied by any explanation (bad for beginners).

由于我不是关于这个问题的一个超级高手我自己,我会作出社区维基让有兴趣的人可以促进和改善了答案。

Since I am not a super-expert on this subject myself, I will make a community WIKI so that anyone interested can contribute and improve the answer.

为了不破坏我的目标是创建一个结构初学者友好WIKI,我想的海报编辑维基时遵循一些简单的原则:

In order not to spoil my purpose to create a structured beginner-friendly WIKI, I'd like the posters to follow a couple of simple guidelines when editing the WIKI:


  • 分类您的使用案例。试试把你的例子/ code已经存在的类别下,如果适用,否则,创建一个新的。

  • Categorize your use case. Try to put your example/code under an already existing category, if applicable, otherwise create a new one.

首先,纯文字说明先用简单的话描述(不简单化,当然 - !质量第一)的例子,或者你正试图使这一点。的然后的投入code样品或引用。

First the plain-words description. First describe with simple words (without oversimplifying, of course - quality first!) the example or the point you are trying to make. Then put code samples or citations.

引用参照标准。请勿张贴的各种标准片段,但给出明确的参考文献(如C99 WG14 / N ... 1.4.7节,第...... )的的张贴链接到相关的资源,如果可能的话。

Cite the standards by reference. Don't post snippets of various standards, but give clear references (e.g C99 WG14/N... section 1.4.7, paragraph ...) and post a link to the relevant resource, if possible.

preFER免费在线资源。如果您想引用书籍或不免费提供的资源,这是确定(并可能提高WIKI的质量),但尝试添加还有一些链接到免费的资源。这是非常重要的尤其是对ISO标准。欢迎您将链接添加到官方标准,但尝试添加相当于链接到免费提供的汇票好。并请不更换与官方标准,引用链接添加草稿给他们。即使是一些计算机科学系在一些大学没有ISO标准(S)的副本,更何况大多数程序员在大的!

Prefer free online resources. If you want to cite books or non-freely available resources that's ok (and may improve the quality of the WIKI), but try to add also some links to free resources. This is really important especially for ISO standards. You are welcome to add links to official standards, but try to add an equivalent link to freely available drafts as well. And please don't replace links to drafts with references to official standards, add to them. Even some Computer Science departments in some universities don't have a copy of the ISO standard(s), let alone most programmers at large!

请勿张贴code,除非确有必要。发表code仅当只使用纯英文的解释是尴尬或不清楚。尝试code样品限制单行。帖子链接到其他SO Q&安培; A而不是

Don't post code unless really necessary. Post code only if an explanation using only plain English would be awkward or unclear. Try to limit code samples to one-liners. Post links to other SO Q&A instead.

请勿张贴的C ++示例。我想这成为一种常见的适用于C (如果有人要启动一个双线程C ++,将是巨大的,虽然)。与C ++相关的差异是受欢迎的,但只作为侧笔记。这就是后你解释C外壳彻底,你可以添加几个关于C语句++,如果切换到C ++时,这将帮助C程序员,但我不希望看到的例子比,也就是说,20%C ++的东西更多。通常是一个简单的音符的(C ++不同的行为在这种情况下)的加相关链接应该够了。

Don't post C++ examples. I'd like this to become a sort of FAQ for C (If someone wants to start a twin-thread for C++ that would be great, though). Relevant differences with C++ are welcome, but only as side-notes. That is after you explain the C case thoroughly you may add a couple of statements about C++ if this would help a C programmer when switching to C++, but I wouldn't want to see examples with more than, say, 20% C++ stuff. Usually a simple note like "(C++ behaves differently in this case)" plus a relevant link should be enough.

由于我是相当新的,所以我希望我不是通过启动Q&放大器违反任何规则; A这种方式。很抱歉,如果是这种情况。 MODS的欢迎让我知道了。

Since I'm fairly new to SO I hope I'm not breaking any rule by starting a Q&A this way. Sorry if this is the case. The mods are welcome to let me know about it.

推荐答案

C类标准定义了USB,UB和IDB的方式,可以归纳如下:

C standards define UsB, UB and IDB in a way that can be summarized as follows:

这是该标准给出了一些替代其中的行为的实施必须选择,但它并不强制如何的选择作出。换句话说,实现必须接受用户code触发该行为不示数出来,必须符合标准中给出的替代品之一。

This is a behavior for which the standard gives some alternatives among which the implementation must choose, but it doesn't mandate how and when the choice is to be made. In other words, the implementation must accept user code triggering that behavior without erroring out and must comply with one of the alternatives given by the standard.

请注意,执行不需要有关文件作出的选择什么。这些选择也可能是不确定的或相关的(在一个未公开的方式)的编译器选项。

Be aware that the implementation is not required to document anything about the choices made. These choices may also be non-deterministic or dependent (in an undocumented way) on compiler options.

要总结:标准给出其中选择一些可能性,实现选择时和特定替代是如何选择和应用

To summarize: the standard gives some possibilities among which to choose, the implementation chooses when and how the specific alternative is selected and applied.

请注意,该标准可以提供一个非常大量的选择。典型的例子是没有被明确初始化的局部变量的初始值。该标准称,该值的未指定的,只要它是变量的数据类型的有效值。

Note that the standard may provide a really large number of alternatives. The typical example is the initial value of local variables that are not explicitly initialized. The standard says that this value is unspecified as long as it is a valid value for the variable's data type.

要更具体考虑的一个 INT 变量:一个实现自由选择任何 INT 价值,这选择可以是完全随机的,非确定性或处于实施率性的怜悯,其中记录它的东西是不需要的。只要保持执行这个是确定的,用户不能抱怨标准规定的范围之内。

To be more specific consider an int variable: an implementation is free to choose any int value, and this choice can be completely random, non-deterministic or be at the mercy of the whims of the implementation, which is not required to document anything about it. As long as the implementation stays within the limits stated by the standard this is ok and the user cannot complain.

由于命名表示,这是在C标准没有规定或保证该计划将或应该做的事情的情况。所有的赌注都关闭。这样的情况:

As the naming indicates this is a situation in which the C standard doesn't impose or guarantee what the program would or should do. All bets are off. Such a situation:


  • 渲染程序要么的错误不可移植

不需要的从实现绝对什么

这是一个非常讨厌的情况:只要有一块code,它是未定义行为,整个程序被认为是错误的实现由允许标准做的一切

This is a really nasty situation: as long as there is a piece of code that has undefined behavior, the entire program is considered erroneous and the implementation is allowed by the standard to do everything.

在换句话说,UB的原因的presence允许执行完全忽略的标准,只要触发UB程序而言。

In other words, the presence of a cause of UB allows the implementation to completely ignore the standard, as long as the program triggering the UB is concerned.

请注意,在这种情况下,实际的行为可以覆盖的可能性的无限范围,以下绝非详尽的清单:

Note that the actual behavior in this case may cover an unlimited range of possibilities, the following is by no means an exhaustive list:


  • 编译时错误的警告。

  • 系统运行时错误的警告。

  • 问题完全被忽略(这可能会导致程序错误)。

  • 编译器默默地投UB- code远作为优化。

  • 您的硬盘可能被格式化。

  • 您的计算机可能会删除您的银行帐户,并要求你的女友约会。

我希望最后两个(一半 -serious)的项目可以给你正确的肠道感慨一下UB的污秽。而且即使大多数实现将不插入必要的code你格式化硬盘,真正的编译器优化做!

I hope the last two (half-serious) items can give you the right gut-feeling about the nastiness of UB. And even though most implementations will not insert the necessary code to format you hard drive, real compilers do optimize!

术语注意:有时人们认为,一些片code的该标准认为UB的的源泉在执行/系统/环境的在形成文件的工作方式, 因此它不能真正UB。 这个推理是错误,但它是一种常见的(而且有些可以理解的)误会:当长期UB(还有USB和IDB)使用的在C环境的是意味着作为一个技术术语,它的 precise 含义由标准(S)定义。特别是单词未定义失去其日常的含义。因此,它没有任何意义,以显示在哪里错误或不可移植程序会产生良好定义的行为的反例。如果你尝试,你真的错过了这一点。 UB意味着你失去了标准的所有保证。如果您的实现提供了一个扩展的再担保是只有你的实现。如果使用该扩展程序不再是标准的C程序(从某种意义上说,它已不再是一个C程序,因为它不遵循标准不再!)。

Terminology Note: Sometimes people argue that some piece of code which the standard deems a source of UB in their implementation/system/environment work in a documented way, therefore it cannot be really UB. This reasoning is wrong, but it is a common (and somewhat understandable) misunderstanding: when the term UB (and also UsB and IDB) is used in a C context it is meant as a technical term whose precise meaning is defined by the standard(s). In particular the word "undefined" loses its everyday meaning. Therefore it doesn't make sense to show examples where erroneous or nonportable programs produce "well-defined" behavior as counterexamples. If you try, you really miss the point. UB means that you lose all the guarantees of the standard. If your implementation provides an extension then your guarantees are only those of your implementation. If you use that extension your program is no more a conforming C program (in a sense, it is no more a C program, since it doesn't follow the standard any longer!).

有关UB一个常见的​​问题是,在这些线路上的东西:?如果UB是那么讨厌,为什么不标准的任务,一个执行问题,当面对UB一个错误

A common question about UB is something on these lines: "If UB is so nasty, why does not the standard mandate that an implementation issues an error when faced with UB?"

首先,优化。从而实现不检查UB的可能原因很多可以优化,使一个C程序极其有效的。这是C的功能之一,但它使ç很多陷阱,对初学的来源。

First, optimizations. Allowing implementations not to check for possible causes of UB allows lots of optimizations that make a C program extremely efficient. This is one of the features of C, although it makes C a source of many pitfalls for beginners.

二,UB在标准的存在允许符合条件的实现提供的扩展以C时不被视为不符合作为一个整体。

Second, the existence of UB in the standards allows a conforming implementation to provide extensions to C without being deemed non-conforming as a whole.

只要实现表现为规定要符合程序,它本身是一致,尽管它可能提供非标准设施,可能是在特定平台上是有用的。当然,使用这些设施的方案将 不可移植并将依托 记录UB ,即是UB行为根据标准,但实施文件作为扩展

As long as an implementation behaves as mandated for a conforming program, it is itself conforming, although it may provide non-standard facilities that may be useful on specific platforms. Of course the programs using those facilities will be nonportable and will rely on documented UB, i.e. behavior that is UB according to the standard, but that an implementation documents as an extension.

这是一个可以在类似于USB A来描述一个行为:该标准规定了一些替代方案和实施选择之一,但要求执行文件的选择究竟是如何制作

This is a behavior that can be described in a way similar to UsB: the standard provides some alternatives and the implementation choose one, but the implementation is required to document exactly how the choice is made.

这意味着,读她的编译器的文档,用户必须考虑的足够的信息以predict究竟会发生什么中的具体情况。

This means that a user reading her compiler's documentation must be given enough information to predict exactly what will happen in the specific case.

需要注意的是,这并不完全记录的IDB的实现不能被视为符合要求。一致性实现必须文件到底是什么,该标准的声明IDB任何情况下发生的。

Note that an implementation that doesn't fully document an IDB cannot be deemed conforming. A conforming implementation must document exactly what happens in any case that the standard declares IDB.





评估函数参数的顺序是不确定的<一个href=\"https://www.securecoding.cert.org/confluence/display/c/EXP30-C.+Do+not+depend+on+the+order+of+evaluation+for+side+effects\"相对=nofollow> EXP30-C 。

The order of evaluation for function arguments is unspecified EXP30-C.

例如, C(A(),B()); 这是不确定的函数是否 A 之前或之后 b 调用。唯一保证是,无论是在 C 函数之前调用。

For instance, in c(a(), b()); it is unspecified whether the function a is called before or after b. The only guarantee is that both are called before the c function.





空指针用于指示一个指针不指向有效的内存。因此,它并没有多大意义,尝试读取或通过一个空指针写入内存。

Null pointers are used to signal that a pointer does not point to valid memory. As such, it does not make much sense to try to read or write to memory via a null pointer.

从技术上说,这是不确定的行为。但是,因为这是错误的一种很常见的来源,大部分C-环境,确保大多数尝试取消引用空指针将立即崩溃的程序(通常是用分段故障杀死它)。这个保护是不完美的,由于涉及到数组和/或结构引用,这样即使有现代工具的指针运算,提领一空指针可以格式化你的硬盘。

Technically, this is undefined behaviour. However, since this is a very common source of bugs, most C-environments ensure that most attempts to dereference a null pointer will immediately crash the program (usually killing it with a segmentation fault). This guard is not perfect due to the pointer arithmetic involved in references to arrays and/or structures, so even with modern tools, dereferencing a null pointer may format your hard drive.

就像空指针,前explitely其值设置取消引用指针UB。不同于空指针,大多数环境不提供针对这种错误的安全网,但编译器可以提醒一下。如果您编译code,无论如何,你可能会遇到UB整个污秽。

Just like null pointers, dereferencing a pointer before explitely setting its value is UB. Unlike for null pointers, most environments do not provide any safety net against this sort of error, except that compiler can warn about it. If you compile your code anyway, you'll are likely to experience the whole nastiness of UB.

这是无效的指针包含没有任何分配的内存区域中的地址指针。创建无效指针常见的方法是调用免费()(呼叫后,指针将是无效的,这是pretty调用的多点免费()),或者使用指针运算来获取超出分配的内存块的极限地址。

An invalid pointer is a pointer that contains an address that is not within any allocated memory area. Common ways to create invalid pointers is to call free() (after the call, the pointer will be invalid, which is pretty much the point of calling free()), or to use pointer arithmetic to get an address that is beyond the limits of an allocated memory block.

这是指针的解引用UB最邪恶的变种:没有安全网,没有编译器警告中,只有一个事实,即code可以做任何事情。和常见的,它的作用:他们希望他们的行为(如安装木马,键盘记录,加密硬盘驱动器等),大多数恶意软件攻击使用这种UB行为的程序,使程序的行为。格式化硬盘驱动器的可能性变得非常现实与这种UB的!

This is the most evil variant of pointer dereferencing UB: There is no safety net, there is no compiler warning, there is just the fact that the code may do anything. And commonly, it does: Most malware attacks use this kind of UB behaviour in programs to make the programs behave as they want them to behave (like installing a trojan, keylogger, encrypting your hard drive etc.). The possibility of a formatted hard drive becomes very real with this kind of UB!

如果我们声明一个对象作为常量 <我们/ em>的给一个承诺,我们永远不会改变对象的值的编译器。在很多情况下编译器都发现这样一个无效的修改和对我们喊。但是,如果我们投的常量性远在这个片段:

If we declare an object as const, we give a promise to the compiler that we will never change the value of that object. In many contexts compilers will spot such an invalid modification and shout at us. But if we cast the constness away as in this snippet:

int const a = 42;
...
int* ap0 = &a;      //< error, compiler will tell us
int* ap1 = (int*)a; //< silences the compiler
...
*ap1 = 43;          //< UB ==> program crash?

编译器可能无法跟踪这种无效访问,编译code到一个可执行文件,并仅在运行时的无效访问将被检测并导致程序崩溃。

the compiler might not be able to track this invalid access, compile the code to an executable and only at run time the invalid access will be detected and lead to a program crash.

把你解释一下!





把你解释一下!

这篇关于未指定的,不确定的,对于C实现定义的行为WIKI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆