几天背面有一个讨论此处是否表达

  

I = ++ i + 1的

调用UB (未定义的行为)或不

最后的结论有人指出它调用UB为“i”是变化的多于两个的序列点之间再次值。

我参与讨论与约翰内斯Schaub的在同一线程。据他

  

I =(I,I ++,i)的1 ------(1)/ *调用UB以及* /

我说(1)不我之间调用UB因为以前的子表达式的副作用是由逗号运算清除“”和我++和我++和我之间。

然后,他给下面的解释:

  

“是该序列点i ++后完成之前所有的副作用,但没有什么停止分配副作用与第i ++副作用重叠。的潜在的问题在于,转让的副作用是未指定后或转让的两个操作数,所以序列点的评估不能对于保护这一做任何事情之前,发生:序列点诱发偏序:正因为有后和前一个序列点i ++不意味着所有副作用相对于测序,以I

     

另外注意,仅仅是一个顺序点意味着什么:评价的顺序并不受代码的形式来决定。它是由语义规则决定的。在这种情况下,不存在语义规则说当分配副作用就恰好评估它的两个操作数或操作数的那些子表达式的的”。

写在“大胆”的说法让我感到困惑。据我知道:

“在在执行顺序称为序列点的某些特定点,先前评价的所有副作用应完整及后续评估的无副作用应已发生。”

因为,逗号运营商也指定我的副作用++当我们到达最后i.He(约翰)已经取消执行顺序将是正确评价过的顺序没有规定被(但在的情况下,逗号运算是公指定)。

所以,我只是想知道是否(1)将调用UB与否?有人可以给另一个有效的解释吗?

谢谢!

有帮助吗?

解决方案

C标准说,这大约赋值运算(C90 6.3.16或C99 6.5.16赋值运算符):

  

更新所述左操作数的存储值的副作用应前一和下一序列点之间发生。

在我看来,在语句:

i=(i,i++,i)+1;

的序列点“之前的”,以赋值运算符将是第二逗号运算和“下一个”点序列将是表达的末尾。所以,我想说的是表达不调用未定义的行为。

然而,此表达式:

*(some_ptr + i) = (i,i++,i)+1;

将有不确定的行为,因为2个操作数赋值运算符的计算顺序是不确定的,在这种情况下,而不是问题是当赋值运算符的副作用发生,问题是你不知道i在左手柄的操作数中使用的值将之前或右侧后进行评估。评估问题的这一顺序,因为在表达i的价值实际上没有在左侧使用不会在第一个例子发生 - 所有的赋值运算符是感兴趣的是“左值性” i

但我也认为,这一切就足够了粗略的(和我所涉及的细微差别的理解足够粗略的),我也不会感到惊讶,如果有人能说服我,否则(无论是计数)。

其他提示

相信下面的表达式肯定有未定义的行为。

i + ((i, i++, i) + 1)

原因在于,逗号运算符在括号指定子表达式之间的序列点,但不指定在该序列+的左手操作数的评价发生。一种可能性是序列点周围i++之间,这违反了5/4的i被写入到两者之间的序列点,但也同样序列点之间两次读取,而不仅仅是确定要存储的价值,而且还确定第一个操作数的运算符+的值。

此也有未定义的行为。

i += (i, i++, i) + 1;

现在,我不敢肯定这个说法。

i = (i, i++, i) + 1;

虽然同样的原理适用,i必须“评估”作为修改的左值,并且可以在任何时间,以便完成,但我不相信它的的是不断的阅读作为此的一部分。 (或者是有,表达违反造成UB另一个限制?)

子表达(i, i++, i)发生作为确定值的一部分,以被存储和该子表达包含i一个值的存储后的顺序点。我没有看到任何方式,这将不需要i++的副作用是完整前要被存储和值的确定,因此最早的可能点时可能发生的分配侧的效果。

在此sequnce点i的价值在读书最多的一次,仅确定将被存回i的价值,所以这最后一部分是好的。

i=(i,i++,i)+1 ------ (1) /* invokes UB as well */

它不调用未定义的行为。 i++的副作用将发生下一个序列点,这是由逗号表示的评价之前它后面,并且还分配之前。

尼斯语言数独,虽然。 : - )

编辑:这里有一个更详细的解释

我很困惑的关于约翰内斯(litb)语句开始,但他提到,在:

i = (i, ++i, i) +1
  

<约翰>结果   如果<一>是分配,并且是一个增量。 :s:是一个顺序点,则副作用序列点之间的顺序如下:(i :s: i++< a ><n> :s: i) + 1。标量i的值在这里,第一和第二序列点之间改变了两次。在其中分配和增量发生的顺序是不确定的,并且由于它们之间没有顺序点,它甚至不是原子相对于每个other.This是一个允许的排序由这些副作用的未指定的排序允许的。

     

这是不同的,以(i++, i++),因为两个子表达式的计算顺序是从左到右,并在它们之间的序列点,先前评估的增量应完整,与接下来的增量不得尚未采取地点。这加强了,有没有i两个序列点之间的值的变化,这使得(i++, i++)有效点击   

这使我觉得由litb提到的序列是无效的,因为每C99为:

  

6.5.16.1(2)在简单赋值(=),右操作数的值被转换为赋值表达式的类型和替换存储在由左操作数所指定的对象的值。

即。需要分配副作用(存储在对应于左操作数的对象的值的修改)

之前被称为右边的操作数的值
  

6.5.17(2)一个逗号操作符的左操作数被评价为空隙表达;还有就是它的评估后的序列点。然后右操作数进行评价;结果有其类型和值。

即。需要逗号操作的最右边的操作数进行评估,以知道逗号表达式的值和类型(和右操作数的用于我的例子的值)。

因此,在这种情况下,对于分配副作用的“先前的序列点”将在效果上是最右边的逗号操作。由约翰提到的可能的序列是无效的。

如果我错了,请大家指正。


scroll top