【问题标题】:Is one side of an assignment sequenced before the other in c++?在 c++ 中,赋值的一侧是否在另一侧之前排序?
【发布时间】:2014-05-21 08:45:06
【问题描述】:

我了解这是未定义的行为:

int i = 0;
int a[4];
a[i] = i++;  //<--- UB here

因为i 对左侧和右侧的求值顺序未定义(; 是唯一的序列点)。

进一步推理,在我看来,这将是 undefined 未指定的行为:

int i = 0;

int foo(){
    return i++;
}

int main(){
    int a[4];
    a[i] = foo();
    return 0;
}

尽管= 的右侧有几个序列点,据我了解,仍然undefined 未指定首先评估f() 还是a[i]

我的假设是否正确?当我在赋值的左侧使用全局或静态变量而右手在任何情况下都不会修改它时,我是否必须小心谨慎?

【问题讨论】:

  • 评估顺序未指定,不是未定义。
  • 函数中的排序仅针对函数。没有定义哪个会先发生,a 的取消引用或函数调用。
  • @chris 感谢您的更正,我的修复正确吗?即第一个未定义而第二个未指定?
  • @PorkyBrain,在第一个 sn-p 下还有一个,但我同意 jrok 的答案。您不会知道它得到什么值,但它会具有两个可能的值之一。

标签: c++ sequence-points


【解决方案1】:
a[i] = foo();

这里未指定是先评估foo 还是a[i]。在新的 C++11 措辞中,这两个评估是无序的。不过,仅此一项并不会导致未定义的行为。当对同一个标量对象进行两次未排序的访问时,其中至少一个是写入,它确实如此。这就是为什么a[i] = i++; 是 UB。

这两个语句之间的区别在于对foo() 的调用确实引入了一个序列点。 C++11 的措辞不同:被调用函数内部的执行相对于调用函数内部的其他评估是不确定的。

这意味着a[i]i++foo 中存在偏序。结果,a[0]a[1] 将被设置为 0,但程序定义明确。

【讨论】:

    【解决方案2】:
    a[i] = i++;
    

    这是未定义的行为,因为i 的值在两个序列点之间被修改和访问(并且访问不直接参与计算i 的下一个值)。 这也是未指定的行为,因为未指定评估的顺序(i 的增量可以发生在使用 i 作为a 的索引之前或之后)。

    当你引入一个函数调用时,比如:

    a[i] = foo();
    

    函数调用引入了另外两个序列点:一个在函数进入之前,一个在函数返回之后。

    这意味着函数内部i的增量被两个序列点包围,不会导致未定义的行为。

    尽管函数调用是在使用 i 作为赋值左侧的索引之前完成,还是之后完成,这仍然是未指定的行为。

    【讨论】:

      猜你喜欢
      • 2019-03-16
      • 2012-06-17
      • 1970-01-01
      • 2018-11-14
      • 2017-10-22
      • 2011-05-27
      • 1970-01-01
      • 2012-07-26
      • 2012-11-14
      相关资源
      最近更新 更多