问题 读取不确定值的未定义行为?


这个问题的答案的评论中出现了这个问题 在对int进行类型转换时,C / C ++ bool类型总是保证为0或1吗?

有问题的代码分配一个(本地)数组 bool 没有初始化他们的价值。

const int n = 100;
bool b[n];

显然,价值观 b 是不确定的。

一些评论者认为阅读,例如 b[0] 未定义的行为。这是在C ++标准中的任何地方陈述的吗?我仍然相信相反:

  1. 显然存储已分配,并且基本bool类型的初始化已完成,因为它没有构造函数。因此,它肯定与解除引用未初始化的指针或在未初始化的非平凡对象上调用方法/强制转换操作符不同。这些具体案例似乎包含在标准中。

  2. C中的行为确实未定义: 在C中声明的未初始化变量会发生什么?它有价值吗? 一些受访者似乎对这两者感到困惑。

  3. 在最新的C ++ 0x草案中,我找不到任何定义 不确定的价值 特别是没有允许访问这样的值来触发处理器陷阱的定义。实际上,Bjarne Stroustrup不确定什么是inderminate值可能是: http://zamanbakshifirst.blogspot.com/2007/02/c-indeterminate-value.html


6566
2017-11-25 16:47


起源

哦,“未定义的行为”在StackOverflow中是一个非常受欢迎的术语,它用于从实现定义到未指定到真正的未定义的所有内容。 - Let_Me_Be
我的意思是众所周知的“鼻子恶魔”。 - Sebastian
顺便说一下。 8.5 - 9谈到这一点。 - Let_Me_Be
@Let_Me_Be:这可能是真的,有时人们可能会错误地将某些案例分类错误,即使他们理解差异。但这是唯一重要的UB,这是标准中定义的意义。 - Steve Jessop
请注意,我的回答 未初始化的局部变量是最快的随机数生成器吗? 也是相关的,我们可以看到编译器正在积极利用围绕不确定值的未定义行为。 - Shafik Yaghmour


答案:


是的,正式地,不确定值的右值转换是UB(除了 unsigned char,最初我写了“和变种”,但我记得正式迎合1的补充签名char,其中可能减去0可以用作陷阱值)

我懒得为你做标准的段落查找,也懒得去关心它的downvotes

然而,实际上只有(1)古老架构和(2)64位系统的问题。

编辑:oops,我现在似乎回想起一篇关于正式UB访问不确定字符的博客文章和相关的缺陷报告。所以也许我必须实际检查标准,+搜索DR。唉,它必须晚些时候,现在咖啡!

EDIT2:Johannes Schaub非常友好地提供了这个 链接到SO问题 讨论了用于访问char的UB的位置。所以,这就是我记得的地方!谢谢,约翰内斯。

干杯和hth。,


4
2017-11-25 16:54



@downvoter:请说明downvote的原因,以便其他人可以了解答案的错误,或者为什么你的downvote是愚蠢的。 - Cheers and hth. - Alf
+1。 4.1 / 1:“非函数非数组类型T的左值(3.10)可以转换为右值。如果T是不完整类型,则需要进行此转换的程序格式不正确。 lvalue引用的不是T类型的对象,也不是从T派生的类型的对象,或者如果对象未初始化,则需要进行此转换的程序具有未定义的行为。 - Steve Jessop
嘿,我不会因为你的懒惰而贬低你。但是,我也许不会赞成它。 - Default
谢谢,我在最新的FCD中找到了相关的段落[conv.lval]。然而, bool& br = b[0] 如果我没有弄错的话,它不是prvalue而是glvalue。问题在于我所做的一切 br (除了赋值)需要转换为右值,对吧? - Sebastian
你的链接指向youtube.com,而不是SO问题。当然有趣,但也许不是你想要的:-) - Sebastian


这个问题的答案随着最新的C ++ 1y工作草案而改变(N3946)我们可以找到 这里。部分 8.5  初始化器 段 12 从C ++ 03和C ++ 11变化很多,现在包含以下内容(强调我的):

如果没有为对象指定初始化程序,则该对象为   默认初始化。 使用自动或自动存储对象时   获得动态存储持续时间,该对象具有  不定   值,如果没有对该对象执行初始化,那   对象保留不确定的值,直到替换该值   (5.17)。 [注意:具有静态或线程存储持续时间的对象是   零初始化,见3.6.2。 - 结束说明] 如果是不确定的值   通过评估产生,行为是不确定的,除了在   以下案例

并继续列出一些例外 无符号窄字符类型 只有,我有一个完整的引用 C ++ 1y在使用不确定值和未定义行为方面有变化吗?

所以在你的情况下 b 具有自动存储持续时间并且未初始化,因此具有不确定的值。所以评估 b[0] 确实是未定义的行为。

以前我们被要求使用左值到右值的转换来证明这是未定义的,但这是有问题的,因为 转换是不明确的

请注意,本节中的不确定值是斜体,因此它意味着它已在适当的位置定义,所以现在C ++ 1y实际上定义了该术语。以前使用的术语没有定义,这包括在内 缺陷报告616


5
2018-05-02 13:34





bool,标准说下 3.9.1基本类型

bool类型的值为true或   假。

用脚注说明:

以所描述的方式使用bool值   按此国际标准    “未定义” 比如通过检查   未初始化的自动值   对象,可能会导致它表现 仿佛   它既不是真也不是假。


3
2017-11-25 18:22





阅读不确定值通常导致未定义行为的事实不仅仅是一个“理论”问题。即使对于所有可能的位模式都有定义值的类型,对于不确定值的行为方式也不应该被认为是“令人惊讶的”,其方式与未指定的值不同。例如,如果* p包含Indeterminate Value,则除了以外的任何地方都不使用x 如图所示,代码:

uint32_t x,y,z;
...
x = *p;
if (condition1) y=x;
... code that "shouldn't" affect *p if its value is defined
if (condition2) z=x;

可以改写为:

if (condition1) y=*p;
... code that "shouldn't" affect *p if its value is defined
if (condition2) z=*p;

如果* p的值为Indeterminate,则不会禁止编译器 从两个“if”语句之间的代码修改其值。 例如,如果* p占用的存储空间被“浮动”占用 在它释放并重新malloc之前,编译器可能会写“浮动” 上面两个“if”语句之间的值。


0
2018-05-07 16:17