【问题标题】:Why cout<<++i + ar[++i]; and cout<<ar[++i]+ ++i; give different output? [duplicate]为什么 cout<<++i + ar[++i];和 cout<<ar[++i]+ ++i;给出不同的输出? [复制]
【发布时间】:2021-12-14 22:44:30
【问题描述】:

我已阅读有关未定义行为的信息。

This Linka[i] = a[i++] 导致未定义的行为。

但我不明白为什么输出

int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int i = 0;
cout << arr[++i] + ++i << " " << i;

3 2

和输出

int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int i = 0;
cout << ++i + arr[++i] << " " << i;

4 2

【问题讨论】:

  • 您是否也已经阅读过此stackoverflow.com/questions/949433/…
  • a[i] = a[i++] 自 C++17 起定义良好
  • 在任何情况下,一个 C++ 问题都不应该作为 C 问题的重复而关闭,因为排序规则不同'
  • 我读过关于 UB。当您同时分配和递增时,它应该适用。但在这里,没有任务。而是使用 cout 递增和打印(未分配) i 的值。
  • "它应该在您同时分配和递增时应用。" - 不必要。看看undefined behavior in C and C++的第6个例子:没有赋值。

标签: c++ language-lawyer pre-increment


【解决方案1】:

首先 - a[i] = a[i++] 从 C++17 开始就定义良好。在该标准的修订版中,排序规则大大收紧,赋值运算符右侧的求值排序在左侧的求值之前,这意味着所有副作用右侧的计算必须在左侧的计算开始之前完成。

所以该代码相当于a[i+1] = a[i]; ++i;


从 C++17 开始,&lt;&lt; 运算符也具有左右排序,即左操作数在右操作数之前排序

现在,++i 被定义为 i+=1,并且与上述类似的考虑适用于复合赋值运算符的评估。 ++i 我们可以说是“原子地”发生的。

但是,+ 运算符仍然是未排序的,这是由 [intro.execution]/17 定义的:

除非另有说明,对单个运算符的操作数和单个表达式的子表达式的求值是无序的

[...]

如果一个内存位置的副作用是unsequenced相对于同一内存位置的另一个副作用或使用同一内存位置中任何对象的值的值计算,它们不是 潜在并发,行为未定义

不幸的是,这意味着++i + a[++i] 的行为仍未定义,因为+ 的左操作数修改了i,而+ 的右操作数修改了i,并且这些操作数评估相对于彼此。


之前有人提议让+ 和类似的运算符也按左右顺序排列,但显然这还没有被标准接受。

【讨论】:

    猜你喜欢
    • 2011-09-22
    • 2011-10-06
    • 2017-10-23
    • 1970-01-01
    • 2014-09-04
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 2020-11-25
    相关资源
    最近更新 更多