繁体   English   中英

C11表达式中的赋值运算符排序

[英]Assignment operator sequencing in C11 expressions

介绍

C11标准(ISO / IEC 9899:2011)在表达式中引入了新的副作用测序定义( 参见相关问题 )。 序列点概念已经关系之前进行了序列补充,并且关系之后 进行了 排序,这些关系现在是所有定义的基础。

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

如果相对于对同一标量对象的不同副作用或使用相同标量对象的值进行值计算,对标量对象的副作用未被排序,则行为未定义。 如果表达式的子表达式有多个允许的排序,则如果在任何排序中发生这种未测序的副作用,则行为是不确定的。

稍后,第6.5.16节“分配操作员”,第3点指出:

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

问题

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

第一个例子

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

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

  1. 如果相对于(...)使用相同标量对象的值进行值计算,标量对象的副作用未被排序,则行为未定义。 (6.5 / 2),
  2. 对操作数的评估是不确定的。 [在作业内](6.5.16 / 3)。

因此, i++ (LHS)的副作用与i (RHS)无关,它给出了未定义的行为。

第二个例子

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

但是,此代码似乎在两种情况下都会导致定义的行为:

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

因此, ++i + 1的执行应先于更新i的副作用,这意味着相对于对同一标量对象的不同副作用或使用的值计算,对未标测的标量对象没有副作用相同标量对象的值。

使用C99标准提出的术语和定义很容易解释这些例子( 参见相关问题 )。 但根据C11的术语,为什么i = ++i + 1未定义?

更新

我在这里改变我的答案,虽然它是在C ++ 11中,但在C11中没有很好地定义。 这里的关键是++i的结果不是左值,因此在评估++i之后不需要进行左值到右值的转换,因此我们无法保证将读取++i的结果然后。 这与C ++不同,因此我最初链接的缺陷报告取决于这个关键事实:

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

我们可以通过转到C11草案标准部分6.5.3.1 前缀增量和减量运算符来看到这一点:

[...]表达式++ E相当于(E + = 1)。[...]

然后是6.5.16 分配操作员强调我的前进 ):

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

和脚注111说:

允许实现读取对象以确定值,但不需要,即使对象具有volatile限定类型。

即使它是易失性的,也不需要读取对象来确定它的值。

原始答案

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

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

 i = ++i + 1; 

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

并且解决方案是打击前缀示例并使用后缀示例,而这显然是未定义的:

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

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

在您正确引用时,标准规定了分配(6.5.16)

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

(增量运算符没有区别,它只是伪装的赋值)

这意味着有两个值计算(左和右),然后在这些值之后对赋值的副作用进行排序。 但它仅针对价值计算进行排序,而不是针对这些可能产生的副作用。 所以最后我们面临着两个副作用( =运算符和++运算符),它们彼此之间没有顺序。

但根据C11的术语,为什么i = ++i + 1未定义?

C11说,在留下的副作用, i被测序但不是左边和右边的值计算(评估) i
很明显,LHS的副作用将在评估LHS和RHS的表达后发生。
为了解释这个,可以有一个更好的例子

int i = 1;
i = i++ + 3;

(首先让我们假设这个例子不会调用UB)。 现在i的最终值可能是42
案例1
左边的i被取出然后它被递增并且3被添加到它,最后4被分配给i
案例2
左边是i ,然后将3添加到它,然后将4分配给i ,最后i递增。 在这种情况下, i的最终值为2
尽管对左i的副作用是有序的,但是没有定义存储到i的最终值,即它不一定是由赋值,因此对i的副作用是未定序的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM