未定义的行为或误报
我(基本上)在野外遇到了以下内容,
x = x = 5;
它显然可以在早期版本的 gcc 下干净地编译(在 gcc 4.5.1 下生成警告)。据我所知,警告是由 -Wsequence-point 生成的。所以我的问题是,这是否违反了标准中关于在序列点之间操作变量的措辞(即,它是根据规范的未定义行为),还是这是 gcc 误报(即,它是根据规范定义的行为)?关于序列点的措辞有点难以理解。
我之所以这么说,是因为我实际上遇到的(以更大的表达方式)是,
x[0][0] = x[0][0] = 5;
但我认为这对警告来说并不重要(如果这是重点,而不是我所认为的关键问题,请纠正我)事情)。
I've (essentially) come across the following in the wild
x = x = 5;
which apparently compiles cleanly under earlier version of gcc (generates a warning under gcc 4.5.1). As far as I can tell the warning is generated by -Wsequence-point. So my question is does this violate the wording in the standard about manipulating variables in between sequence points (i.e., it is undefined behavior per the spec) or is this a gcc false positive (i.e., it is defined behavior per the spec)? The wording on sequence points is a bit hard to follow.
I said essentially because what I actually came across (in a larger expression) was
x[0][0] = x[0][0] = 5;
but I didn't think that was material to the warning (please correct me if that is to the point and not what I've assumed is the crux of the matter).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
假设 x 是内置类型,它会分配给 x 两次,而无需插入序列点,这就是您需要知道的全部内容。事实上,两个赋值具有相同的值 (5),并且理论上可以优化为单个赋值(如果 x 不是易失性的),这一点既不存在也不存在。
至少,这就是我在标准中解释“修改”的方式 - 分配一个值,无论它是否恰好与旧值相同。同样,我认为,抛弃 const 并分配给 const 对象是 UB,无论您分配的值是否恰好等于先前的值。否则,如果一个实现想要将字符串文字放入 ROM 中,以防止在这种情况下出现页面错误,那么所有内存写入都会产生巨大的开销,并且通过检查我们知道编译器不会发出该代码。
一个更令人兴奋的例子是 x[0][0] = x[0][i] = 5;,它在没有插入序列点的情况下分配给同一个对象当(且仅当)
i == 0
,因此定义的行为以i
的值为条件。我不太明白为什么编译器在这两种情况下都会做一些意想不到的事情,但我的想象力的缺乏是无关紧要的:-)
ablenky 说的是对的。如果您在某些上下文中无法使用两个语句,则可以编写
x[0][0] = 5, x[0][i] = 5
来代替。在您给定的两种情况下,只需放弃多余的分配即可。Assuming
x
is of built-in type, it assigns tox
twice without an intervening sequence point, which is all you need to know. The fact that both assignments are of the same value (5), and could in theory be optimized into a single assignment (ifx
is not volatile), is neither here nor there.At least, that's how I interpret "modified" in the standard - assigned a value, regardless of whether it happens to be the same as the old value. Likewise, casting away const and assigning to a const object is, I think, UB regardless of whether the value you assign happens to be equal to the prior value. Otherwise there's be a huge overhead on all memory writes if an implementation wanted to put string literals into ROM, to prevent a page fault in that case, and we know by inspection that compilers don't emit that code.
A even more exciting example would be
x[0][0] = x[0][i] = 5;
, which assigns to the same object without an intervening sequence point if (and only if)i == 0
, so is defined behaviour conditional on the value ofi
.I don't see quite why a compiler might do anything unexpected in either case, but again my lack of imagination is irrelevant :-)
What ablenky says is right. If you're in some context where you can't use two statements, maybe write
x[0][0] = 5, x[0][i] = 5
instead. In both your given cases, just ditch the redundant assignment.