在C和c++中,什么是未定义的行为(UB) ?未指定的行为和实现定义的行为呢?它们之间的区别是什么?
当前回答
Historically, both Implementation-Defined Behavior and Undefined Behavior represented situations in which the authors of the Standard expected that people writing quality implementations would use judgment to decide what behavioral guarantees, if any, would be useful for programs in the intended application field running on the intended targets. The needs of high-end number-crunching code are quite different from those of low-level systems code, and both UB and IDB give compiler writers flexibility to meet those different needs. Neither category mandates that implementations behave in a way that's useful for any particular purpose, or even for any purpose whatsoever. Quality implementations that claim to be suitable for a particular purpose, however, should behave in a manner befitting such purpose whether the Standard requires it or not.
The only difference between Implementation-Defined Behavior and Undefined Behavior is that the former requires that implementations define and document a consistent behavior even in cases where nothing the implementation could possibly do would be useful. The dividing line between them is not whether it would generally be useful for implementations to define behaviors (compiler writers should define useful behaviors when practical whether the Standard requires them to or not) but whether there might be implementations where defining a behavior would be simultaneously costly and useless. A judgment that such implementations might exist does not in any way, shape, or form, imply any judgment about the usefulness of supporting a defined behavior on other platforms.
不幸的是,自20世纪90年代中期以来,编译器作者开始将缺乏行为授权解释为一种判断,即行为保证不值得付出代价,即使在它们至关重要的应用领域,甚至在它们几乎不花费任何成本的系统上。编译器编写者不再将UB视为进行合理判断的邀请,而是开始将其视为不这样做的借口。
例如,给定以下代码:
int scaled_velocity(int v, unsigned char pow)
{
if (v > 250)
v = 250;
if (v < -250)
v = -250;
return v << pow;
}
两个互补的实现不需要花费任何精力 将表达式v << pow视为二补移位 不管v是正还是负。
The preferred philosophy among some of today's compiler writers, however, would suggest that because v can only be negative if the program is going to engage in Undefined Behavior, there's no reason to have the program clip the negative range of v. Even though left-shifting of negative values used to be supported on every single compiler of significance, and a large amount of existing code relies upon that behavior, modern philosophy would interpret the fact that the Standard says that left-shifting negative values is UB as implying that compiler writers should feel free to ignore that.
其他回答
好吧,这基本上是直接从标准复制粘贴
3.4.1 1 implementation-defined behavior unspecified behavior where each implementation documents how the choice is made 2 EXAMPLE An example of implementation-defined behavior is the propagation of the high-order bit when a signed integer is shifted right. 3.4.3 1 undefined behavior behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements 2 NOTE Possible 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). 3 EXAMPLE An example of undefined behavior is the behavior on integer overflow. 3.4.4 1 unspecified behavior use of an unspecified value, or other behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance 2 EXAMPLE An example of unspecified behavior is the order in which the arguments to a function are evaluated.
Historically, both Implementation-Defined Behavior and Undefined Behavior represented situations in which the authors of the Standard expected that people writing quality implementations would use judgment to decide what behavioral guarantees, if any, would be useful for programs in the intended application field running on the intended targets. The needs of high-end number-crunching code are quite different from those of low-level systems code, and both UB and IDB give compiler writers flexibility to meet those different needs. Neither category mandates that implementations behave in a way that's useful for any particular purpose, or even for any purpose whatsoever. Quality implementations that claim to be suitable for a particular purpose, however, should behave in a manner befitting such purpose whether the Standard requires it or not.
The only difference between Implementation-Defined Behavior and Undefined Behavior is that the former requires that implementations define and document a consistent behavior even in cases where nothing the implementation could possibly do would be useful. The dividing line between them is not whether it would generally be useful for implementations to define behaviors (compiler writers should define useful behaviors when practical whether the Standard requires them to or not) but whether there might be implementations where defining a behavior would be simultaneously costly and useless. A judgment that such implementations might exist does not in any way, shape, or form, imply any judgment about the usefulness of supporting a defined behavior on other platforms.
不幸的是,自20世纪90年代中期以来,编译器作者开始将缺乏行为授权解释为一种判断,即行为保证不值得付出代价,即使在它们至关重要的应用领域,甚至在它们几乎不花费任何成本的系统上。编译器编写者不再将UB视为进行合理判断的邀请,而是开始将其视为不这样做的借口。
例如,给定以下代码:
int scaled_velocity(int v, unsigned char pow)
{
if (v > 250)
v = 250;
if (v < -250)
v = -250;
return v << pow;
}
两个互补的实现不需要花费任何精力 将表达式v << pow视为二补移位 不管v是正还是负。
The preferred philosophy among some of today's compiler writers, however, would suggest that because v can only be negative if the program is going to engage in Undefined Behavior, there's no reason to have the program clip the negative range of v. Even though left-shifting of negative values used to be supported on every single compiler of significance, and a large amount of existing code relies upon that behavior, modern philosophy would interpret the fact that the Standard says that left-shifting negative values is UB as implying that compiler writers should feel free to ignore that.
c++标准n3337§1.3.10 实现定义的行为
行为,对于结构良好的程序构造和正确的数据,即 这取决于实现和每个实现文档
有时候c++标准并没有把特定的行为强加给某些结构,而是说一个特定的、定义良好的行为必须由特定的实现(库的版本)选择和描述。所以用户仍然可以确切地知道程序的行为,即使标准没有描述这一点。
c++标准n3337§1.3.24 未定义的行为
behavior for which this International Standard imposes no requirements [ Note: Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. 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). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. — end note ]
当程序遇到不是根据c++标准定义的构造时,它可以做任何它想做的事情(可能给我发一封电子邮件,也可能给你发一封电子邮件,或者可能完全忽略代码)。
c++标准n3337§1.3.25 未指明的行为
行为,对于结构良好的程序构造和正确的数据,即 依赖于实现[注:实现不是 需要记录发生的行为。可能的范围 行为通常是由本国际标准来描述的。- - -结束 请注意)
c++标准没有将特定的行为强加于某些结构,而是说特定的、定义良好的行为必须由特定的实现(库的版本)选择(bot没有必要描述)。因此,在没有提供描述的情况下,用户很难确切地知道程序将如何运行。
未定义行为vs.未指定行为有一个简短的描述。
他们最后的总结是:
总而言之,未指定的行为通常是不应该发生的 担心,除非你的软件被要求是可移植的。 相反,未定义的行为总是不受欢迎的,也不应该这样做 发生。
未定义的行为是丑陋的——比如“好的、坏的和丑陋的”。
好:一个能够编译并正常工作的程序。
坏的:有错误的程序,这种错误编译器可以检测到并报错。
丑陋的:一个程序有一个错误,编译器不能检测和警告,这意味着程序编译,可能在某些时候正确工作,但也在某些时候奇怪地失败。这就是未定义行为。
一些程序语言和其他正式系统努力限制“不确定性的鸿沟”——也就是说,它们试图安排事情,使大多数或所有程序不是“好”就是“坏”,只有极少数程序是“丑”的。然而,这是C语言的一个特征,它的“不确定性的鸿沟”相当宽。
推荐文章
- 为什么STL如此严重地基于模板而不是继承?
- 查找当前可执行文件的路径,不包含/proc/self/exe
- 未定义对静态constexpr char的引用[]
- 在c++中,restrict关键字是什么意思?
- 如何创建可变参数宏(参数数量可变)
- c++中类似于java的instanceof
- include_directories和target_include_directories在CMake中的区别是什么?
- std::make_pair与std::pair的构造函数的目的是什么?
- 如何追加一个字符到std::字符串?
- 为什么C语言这么快,为什么其他语言没有这么快或更快?
- 转发C中可变函数的调用
- 为什么要在c++中使用嵌套类?
- 如何处理11000行c++源文件?
- 使用g++编译多个.cpp和.h文件
- 当尝试用const初始化变量时,错误“初始化元素不是常量”