C11表达式中的运算符排序 [英] Assignment operator sequencing in C11 expressions

查看:172
本文介绍了C11表达式中的运算符排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C11标准(ISO / IEC 9899:2011)在表达式中引入了副作用序列的新定义(查看相关问题)。 序列点概念在和之前的序列之后被补充,这些关系现在是所有定义的基础。

The C11 standard (ISO/IEC 9899:2011) has introduced a new definition of side effect sequencing within an expression (see related question). The sequence point concept has been complemented with sequenced before and sequenced after relations which are now the basis for all definitions.

第6.5节表达式,第2点说:

Section 6.5 "Expressions", point 2 says:


如果标量对象的副作用是相对于相同标量对象上的不同副作用
或使用相同标量
对象的值进行值计算,未排序,行为是未定义的。如果表达式的
子表达式有多个允许的排序,则如果在任何排序中出现这样一个未排序的边
效果,行为是未定义的。

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.

稍后,第6.5.16节作业操作员,第3点说明:

Later on, section 6.5.16 "Assignment operators", point 3 states:


更新左操作数的存储值的副作用在左右操作数的值计算之后进行排序。
的操作数的评估是未排序的。

The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced.



问题



第一个引用的段落(6.5 / 2)由两个示例(与C99标准相同)支持:

Problem

The first quoted paragraph (6.5/2) is supported by two examples (same as in the C99 standard):

a[i++] = i;  //! undefined
a[i] = i;    //  allowed

这可以通过定义轻松解释:

This can be easily explained with the definitions:


  1. 如果标量对象的副作用相对于(...)使用相同标量对象的值的值计算未排序,则行为是未定义的。 (6.5 / 2),

  2. 操作数的评估未排序。 [在作业内](6.5.16 / 3) / li>
  1. If a side effect on a scalar object is unsequenced relative to (...) a value computation using the value of the same scalar object, the behavior is undefined. (6.5/2),
  2. The evaluations of the operands are unsequenced. [within an assignment] (6.5.16/3).

所以, i ++ (LHS)的副作用不符合<$

So, the side effect of i++ (LHS) is unsequenced with i (RHS), which gives undefined behaviour.

i = ++i + 1; //! undefined
i = i + 1;   //  allowed

但是,这段代码似乎在给定的情况下导致了一个定义的行为:

This code, however, seems to result in a defined behaviour in both given cases as:


  1. 更新左操作数的存储值的副作用在左右操作数的值计算之后进行排序。

  1. the side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands.

所以执行 ++ i + 1
应在更新 i 的副作用之前,这意味着相对于不同的副作用,标量对象没有顺序的副作用在相同的标量对象上或使用相同标量对象的值计算值。

So, the execution of ++i + 1 shall precede the side effect of updating i, which means that there is not a side effect on a scalar object unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object.

很容易用C99标准提供的术语和定义来解释这些例子(查看相关问题)。但是为什么根据C11的术语来定义 i = ++ i + 1

It is easy to explain these examples with the terms and definitions presented by the C99 standard (see related question). But why is i = ++i + 1 undefined according to C11's terminology?

推荐答案

更新

我正在更改我的答案,这在C11中没有很好的定义,尽管它在C ++ 11中。这里的关键是, ++ i 的结果不是一个左值,因此在 ++ i之后不需要进行lvalue-to-rvalue转换被评估,所以我们不能放心,以后会读取 ++ i 的结果。这与C ++不同,因此我最初链接的缺陷报告取决于这个关键事实:

I am changing my answer here, this is not well defined in C11 although it is in C++11. The key here is that the result of ++i is not an lvalue and therefore does not require an lvalue-to-rvalue conversion after ++i is evaluated and so we can not be assured that the result of ++i will be read afterwards. Which is different than C++ and so the defect report I originally linked to hinges on this critical fact:


[...] lvalue表达式++然后我对结果进行了一个左值对值的转换。保证增加副作用在计算加法运算之前进行排序[...]

[...] the lvalue expression ++i and then do an lvalue-to-rvalue conversion on the result. guarantees that the incrementation side-effect is sequenced before the computation of the addition operation[...]

我们可以看到< 6.5.3.1 前缀增减运算符说:


[...] ++ E等效于(E + = 1)。[...]

[...]The expression ++E is equivalent to (E+=1).[...]

然后部分说明(强调我的前进):

and then section 6.5.16 Assignment operators which says (emphasis mine going forward):


赋值运算符将值存储在左操作数指定的对象中。一个
赋值表达式具有分配后的左操作数的值, 111 但不是一个左值。[...]

和脚注 111 说:


即使对象具有volatile限定类型,实现也可以读取对象来确定值,但不是必需的。

The implementation is permitted to read the object to determine the value but is not required to, even when the object has volatile-qualified type.

没有必要阅读对象来确定它的价值,即使它是挥发性的。

There is no requirement to read the object to determine it's value even if it is volatile.

原始答案

据我所知,这实际上是很明确的,这个例子是从使用类似语言的C ++草案标准中删除的。我们可以在 637中看到这一点。顺序规则
和示例不同意
,其中说:

As far as I can tell this is actually well defined and this example was removed from the C++ draft standard which uses similar language. We can see this in 637. Sequencing rules and example disagree which says:


以下表达式仍然列为未定义行为的示例:

the following expression is still listed as an example of undefined behavior:

i = ++i + 1;

但是,新的排序规则似乎使得这个表达式定义明确:

However, it appears that the new sequencing rules make this expression well-defined:

,该分辨率是为了打击前缀示例,并使用后缀示例,而这显然是未定义的:

and the resolution was to strike the prefix example and use the postfix example instead which is clearly undefined:


更改1.9 [intro.execution]段落16中的示例如下:

Change the example in 1.9 [intro.execution] paragraph 16 as follows:

i = ++ i i ++ + 1; //行为未定义

i = ++i i++ + 1; // the behavior is undefined

这篇关于C11表达式中的运算符排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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