是否存在“未定义行为"?真的允许*任何事情*发生吗?
未定义行为"的经典杜撰示例;当然是鼻恶魔".― 物理上不可能,无论 C 和 C++ 标准允许什么.
The classic apocryphal example of "undefined behavior" is, of course, "nasal demons" ― a physical impossibility, regardless of what the C and C++ standards permit.
因为 C 和 C++ 社区倾向于强调未定义行为的不可预测性以及允许编译器在遇到未定义行为时使程序按字面意思执行任何事情的想法,我曾假设该标准对未定义行为的行为没有任何限制.
Because the C and C++ communities tend to put such an emphasis on the unpredictability of undefined behavior and the idea that the compiler is allowed to cause the program to do literally anything when undefined behavior is encountered, I had assumed that the standard puts no restrictions whatsoever on the behavior of, well, undefined behavior.
但是C++ 标准中的相关引用似乎是一个>:
[C++14: defns.undefined]:
[..] 允许的未定义行为范围从完全忽略具有不可预测结果的情况到在翻译或以环境特征的文件化方式执行程序(发出或不发出诊断消息),终止翻译或执行(发出诊断消息).[..]
[C++14: defns.undefined]:
[..] Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). [..]
这实际上指定了一小组可能的选项:
This actually specifies a small set of possible options:
- 忽略情况 -- 是的,标准继续说这将产生不可预测的结果",但这与编译器插入代码不同(我认为这是鼻恶魔的先决条件).
- 以有据可查的环境特征行事――这实际上听起来相对温和.(我当然没有听说过任何记录在案的鼻恶魔案例.)
- 终止翻译或执行 -- 至少有诊断.如果所有 UB 都会表现得这么好.
- Ignoring the situation -- Yes, the standard goes on to say that this will have "unpredictable results", but that's not the same as the compiler inserting code (which I assume would be a prerequisite for, you know, nasal demons).
- Behaving in a documented manner characteristic of the environment -- this actually sounds relatively benign. (I certainly haven't heard of any documented cases of nasal demons.)
- Terminating translation or execution -- with a diagnostic, no less. Would that all UB would behave so nicely.
我假设在大多数情况下,编译器选择忽略未定义的行为;例如,在读取未初始化的内存时,插入任何代码以确保行为一致可能是一种反优化.我想陌生人类型的未定义行为(例如 "")将属于第二类――但这需要记录此类行为并具有环境特征".(所以我猜鼻恶魔只能由地狱般的计算机产生?).
I assume that in most cases, compilers choose to ignore the undefined behavior; for example, when reading uninitialized memory, it would presumably be an anti-optimization to insert any code to ensure consistent behavior. I suppose that the stranger types of undefined behavior (such as "time travel") would fall under the second category--but this requires that such behaviors be documented and "characteristic of the environment" (so I guess nasal demons are only produced by infernal computers?).
我误解了定义吗?这些是否只是示例可能构成未定义行为的内容,而不是一个完整的选项列表?是否声称任何事情都可能发生"?仅仅意味着忽略这种情况的意外副作用?
Am I misunderstanding the definition? Are these intended as mere examples of what could constitute undefined behavior, rather than a comprehensive list of options? Is the claim that "anything can happen" meant merely as an unexpected side-effect of ignoring the situation?
澄清两点:
- 我认为最初的问题很清楚,我认为对大多数人来说是这样,但我还是会拼出来:我确实意识到鼻恶魔"是是开玩笑的.
- 请不要写一个(其他)答案来解释 UB 允许特定于平台的编译器优化,除非您也解释它如何允许实现定义的优化行为不允许.
- I thought it was clear from the original question, and I think to most people it was, but I'll spell it out anyway: I do realize that "nasal demons" is tongue-in-cheek.
- Please do not write an(other) answer explaining that UB allows for platform-specific compiler optimizations, unless you also explain how it allows for optimizations that implementation-defined behavior wouldn't allow.
这个问题不是为了讨论未定义行为的(缺点)优点的论坛,但这就是它的结果.在任何情况下,这个线程关于一个假设的 C 编译器没有未定义的行为可能会让那些认为这是一个重要主题的人更感兴趣.
This question was not intended as a forum for discussion about the (de)merits of undefined behavior, but that's sort of what it became. In any case, this thread about a hypothetical C-compiler with no undefined behavior may be of additional interest to those who think this is an important topic.
推荐答案
是的,它允许任何事情发生.注释只是举例说明.定义很明确:
Yes, it permits anything to happen. The note is just giving examples. The definition is pretty clear:
未定义行为:本国际标准未强加任何要求的行为.
Undefined behavior: behavior for which this International Standard imposes no requirements.
<小时>
混淆频率:
您应该理解,无要求"也意味着实现是不需要使行为未定义或做一些奇怪/不确定的事情!
You should understand that "no requirement" also means means the implementation is NOT required to leave the behavior undefined or do something bizarre/nondeterministic!
C++ 标准完全允许该实现记录一些合理的行为并做出相应的行为.1 因此,如果您的编译器声称在有符号溢出时回绕,逻辑(理智?)会规定欢迎您在该编译器上依赖该行为.只是不要期望另一个编译器没有声称的行为方式相同.
The implementation is perfectly allowed by the C++ standard to document some sane behavior and behave accordingly.1 So, if your compiler claims to wrap around on signed overflow, logic (sanity?) would dictate that you're welcome to rely on that behavior on that compiler. Just don't expect another compiler to behave the same way if it doesn't claim to.
1哎呀,它甚至允许记录一件事并做另一件事.那太愚蠢了,而且可能会让你把它扔进垃圾桶――你为什么要相信一个文档对你说谎的编译器?――但这并不违反 C++ 标准.
1Heck, it's even allowed to document one thing and do another. That'd be stupid, and it'd probably make you toss it into the trash―why would you trust a compiler whose documentation lies to you?―but it's not against the C++ standard.
相关文章