在其中C ++标准的版本“(i + = 10)+ = 10”有未定义的行为? [英] In which versions of the C++ standard does "(i+=10)+=10" have undefined behaviour?

查看:114
本文介绍了在其中C ++标准的版本“(i + = 10)+ = 10”有未定义的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C ++中,以下是否有未定义的行为:

In C++, does the following have undefined behaviour:

int i = 0;
(i+=10)+=10;

我的回答 在C和C ++中+ =的结果是什么?这里的细微之处是,默认响应似乎是是,而正确的答案是它取决于C ++标准的版本。

There was some debate about this in the comments to my answer to What's the result of += in C and C++? The subtlety here is that the default response seems to be "yes", whereas it appears that the correct answer is "it depends on the version of the C++ standard".

如果它依赖于标准的版本,请解释UB在哪里和不在哪里。

If it does depend on the version of the standard, please explain where it's UB and where it's not.

推荐答案

tl; dr (i + = 10)+中执行的修改和读取的< = 10 在C ++ 98和C ++ 11中都有明确定义,但是在C ++ 98中这不足以使行为定义。

tl;dr: The sequence of the modifications and reads performed in (i+=10)+=10 is well defined in both C++98 and C++11, however in C++98 this is not sufficient to make the behavior defined.

在C ++ 98中,对同一对象进行多次修改而没有插入序列点会导致未定义的行为,即使这些修改的顺序已明确指定。这个表达式不包含任何序列点,所以它由两个修改组成的事实足以使其行为未定义。

In C++98 multiple modifications to the same object without an intervening sequence-point results in undefined behavior, even when the order of those modifications is well specified. This expression does not contain any sequence points and so the fact that it consists of two modifications is sufficient to render its behavior undefined.

C ++ 11没有序列点并且仅需要对对象的修改相对于彼此排序并且读取相同对象以产生定义的行为。

C++11 doesn't have sequence points and only requires that the modifications of an object be ordered with respect to each other and to reads of the same object to produce defined behavior.

因此,行为是未定义的C ++ 98,但在C ++ 11中定义良好。

Therefore the behavior is undefined in C++98 but well defined in C++11.

C ++ 98子句[expr] 5 p4

C++98 clause [expr] 5 p4


除非另有说明,

Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expression, and the order in which side effects take place, is unspecified.

C ++ 98子句[expr.ass] 5.17 p1

C++98 clause [expr.ass] 5.17 p1


赋值操作的结果是赋值之后存储在左操作数中的值;结果是一个左值

The result of the assignment operation is the value stored in the left operand after the assignment has taken place; the result is an lvalue

所以我相信的顺序是指定的,但我不认为那个单独是足够创建序列点在表达式中间。继续使用[expr] 5 p4的引号:

So I believe the order is specified, however I don't see that that alone is enough to create a sequence point in the middle of an expression. And continuing on with the quote of [expr] 5 p4:


在上一个和下一个序列点之间,标量对象应具有其存储值

Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression.

所以即使指定了顺序,我觉得这是不够的对于C ++ 98中的定义行为。

So even though the order is specified it appears to me that this is not sufficient for defined behavior in C++98.

C ++ 11在序列之前和之后的序列之前清除了序列点。来自C ++ 98的语言替换为

C++11 does away sequence points for the much clearer idea of sequence-before and sequenced-after. The language from C++98 is replaced with

C ++ 11 [intro.execution] 1.9 p15

C++11 [intro.execution] 1.9 p15


除非另有说明,否则单个运算符的操作数和单个表达式的子表达式的求值不受影响。 [...]

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...]

如果对标量对象的副作用相对于对同一标量对象的另一个副作用或使用同样的标量对象,行为是未定义的。

If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

C ++ 11 [expr.ass] 5.17 p1

C++11 [expr.ass] 5.17 p1


在所有情况下,赋值在右和左操作数的值计算之后,在赋值表达式的值计算之前排序。

In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.

因此,虽然排序不足以使C ++ 98中定义的行为,C ++ 11已经改变了要求,

So while being ordered was not sufficient to make the behavior defined in C++98, C++11 has changed the requirement such that being ordered (i.e., sequenced) is sufficient.

(在我看来,'sequence before'和'sequenced after'后所提供的额外灵活性导致了更加清晰,一致,以及指定的语言。)

(And it seems to me that the extra flexibility afforded by 'sequence before' and 'sequenced after' has lead to a much more clear, consistent, and well specified language.)

我似乎不太可能任何C ++ 98实现会做任何令人惊讶的当操作序列被良好指定时,即使不足以产生技术上良好定义的行为。作为一个例子,Clang在C ++ 98模式下产生的这个表达式的内部表示具有良好定义的行为,并且是预期的东西。

It seems unlikely to me that any C++98 implementation would actually do anything surprising when the sequence of operations is well specified even if that is insufficient to produce technically well defined behavior. As an example, the internal representation of this expression produced by Clang in C++98 mode has well defined behavior and does the expected thing.

这篇关于在其中C ++标准的版本“(i + = 10)+ = 10”有未定义的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆