detailed explanation标签的undefined-behavior开始得很合理:
在计算机编程中,未定义的行为(非正式地为“ UB”)是指 到程序未指定其行为的计算机代码 特定条件下的语言标准。
但随后说(强调我的意思):
有关记录的未定义行为的各种形式的疑问 用给定的编程语言。
如何“记录”“未指定”的“行为”?
什么是“记录在案的未定义行为”?哪些语言有这种野兽?
[附加评论:
不同的人以不同的方式解释了先前引用的文本,甚至具有相反的含义,因此,这个问题从本质上成为了对文本进行澄清和重写的请求,这自然适合于meta 。但是问题不是 主要是请求更改标签说明,而是编程语言的问题,因此有意不将其发布在meta 上。
(注意:我已经在问题和答案中多次提到过该文本的问题,但是每次删除我的评论时,都会采用非常苛刻的方式。)
编辑
请编辑以详细说明问题的哪些部分 独特
同样,独特的部分是:
没有链接的问题回答这些问题; 记录的未定义行为一词甚至都不会一起出现。
如果我错过了一些事情,专门指出解释这些问题的答案会很有帮助。
我很遗憾要删除关于UB的另一个问题,答案或讨论,因为它指出了标记说明中的不一致之处。
答案 0 :(得分:2)
我是在Wiki中写这些文字的人。我所说的“记录的未定义行为”指的是语言标准中形式上未定义的行为,但在现实世界中定义得很好。没有语言记录“未定义的行为”,但是现实世界并不总是在乎语言标准的内容。
一个更好的术语可能是非标准语言扩展,或者如果您“就编程语言标准而言仍未定义”。
在语言标准中某些东西被视为未定义行为的原因有很多:
示例1)
变量在哪里存储在内存中?这超出了标准的范围,但在执行程序的任何计算机上定义都很好。
类似地,如果我说“我的猫是黑色的”,这是未定义的行为,因为编程语言未涵盖猫的颜色。这并不意味着我的猫会突然在神秘色彩的万花筒中闪闪发光,而是现实优先于理论编程标准。我们可以完全确定,即使特定的猫是未定义的行为,它也永远是黑猫。
示例2)
有符号整数溢出。在整数级溢出的情况下,在CPU级别上完全可以很好地定义。在大多数情况下,该值本身将被视为简单的无符号加/减,但是将在状态寄存器中设置一个溢出标志。就C或C ++语言而言,从理论上讲,此类溢出可能导致发生可怕的,无法解释的事件。但是实际上,底层硬件将产生完美定义的结果。
示例3)
被零除。访问无效的地址。堆栈溢出时的行为。等等
答案 1 :(得分:1)
C和C ++相当独特,因为“官方” C标准是在该语言已经使用很久之后才编写的,甚至在已出版的书中都有描述。有许多情况,例如整数溢出,某些实现将以记录的可预测方式进行处理,而另一些则不能廉价地实现。该标准将此类事物视为“未定义的行为”,明确指出实现可能(但不是必需)以文档化的环境特征处理它们。请注意,这允许在某些环境中保证任何种类的一致行为的代价都很高,并且尽管付出了代价,许多程序仍可能无法提供此类保证。
例如,考虑以下内容:
extern volatile int someFlag;
void test(int x, int y)
{
int z;
someFlag = 1;
z=x+y;
someFlag = 0;
if (f2())
f3(x,y,z);
}
应该允许溢出引发信号的实现将代码更改为:
extern volatile sig_atomic_t someFlag;
void test(int x, int y)
{
someFlag = 1;
someFlag = 0;
if (f2())
f3(x,y,x+y);
}
这样做可以避免在对x+y
的调用中将f2()
的值保存在内存中,并且可以避免完全计算它的需要。除非{em} {em> {em} someFlag
的净赢将以代码所依赖的方式影响整数溢出信号的行为。如果该标准将整数溢出的特征描述为“实现定义”,则在没有上述优化措施的情况下,实现记录标准所要求的溢出行为将是很尴尬的,即使出于许多目的,也可以保证在执行加法之前调用f2
会增加成本,但没有任何价值。
该标准的作者不是试图担心是否应该允许或禁止这种优化,而是选择将整数溢出的特征描述为“未定义行为”,从而允许记录其行为的实现方式继续这样做,但不要求实现者悲观地假设可能以他们不知道的方式观察到任何可能的副作用。在编写本标准之前,实施记录的任何行为都应记录为行为,并且本标准将行为描述为未定义的事实无意于对此进行更改。
自那时以来,已经有许多缺陷报告错误地将符合但不严格符合的各种构造描述为“不符合”,这导致人们误认为标准中的术语“ X是未定义的”等同于“ X被禁止”。其他语言规范在区分禁止和必须诊断的构造,禁止但可能并非总是被诊断的构造,预期其行为是部分但不完全一致的构造,以及其行为将在以下方面表现出的构造方面,则更为明确。在不同的实现上使用不同的一致方式,但是原始C和C ++标准的作者将这些东西留给了实现者的判断。
答案 2 :(得分:0)
在我读到它时,“记录的未定义行为”并不表示“两者(未定义并记录)的行为”。它的意思是“(已记录的未定义行为)”。他甚至举了一个例子:
例如,如果在编译过程中知道数组索引,则编译器可能会诊断出访问C中数组最后一个元素的情况,或者可能会从未初始化的内存返回垃圾值,或者返回明显的值,或者导致通过访问进程数据地址空间之外的内存使程序崩溃。
未定义的行为是“访问C中数组的最后一个元素之外”。 C语言说,这是未定义的。但是,他和其他人已经记录了当您进入语言的“未定义”区域时,真实单词中实际发生的事情。
因此,记录了两个未定义行为的级别。
1)被识别。 “ C不定义当您经过数组末尾时会发生什么”。现在您知道这是未定义的行为。
2)被探索。 “当您这样做时,可能会发生一些事情。”
作者可能打算表达1或2。但是我认为您所追求的含义可能是与我阅读该短语不同的人工产物。