【问题标题】:Shift operands sequenced in C++17在 C++17 中排序的移位操作数
【发布时间】:2019-01-17 23:17:51
【问题描述】:

我阅读了 C++17 标准 $8.5.7.4:

表达式 E1 在表达式 E2 之前排序。

用于移位运算符。

另外cppreference 规则 19 说:

在移位运算符表达式 E1E2 中,E1 的每个值计算和副作用都排在 E2 的每个值计算和副作用之前

但是当我尝试使用 gcc 7.3.0 或 clang 6.0.0 编译以下代码时

#include <iostream>
using namespace std;

int main() {
    int i = 5;
    cout << (i++ << i) << endl;
    return 0;
}

我收到以下 gcc 警告:

../src/Cpp_shift.cpp: In function ‘int main()’:
../src/Cpp_shift.cpp:6:12: warning: operation on ‘i’ may be undefined [-Wsequence-point]
  cout << (i++ << i) << endl;
           ~^~

叮当警告是:

warning: unsequenced modification and access to 'i' [-Wunsequenced]

我使用以下命令编译:

g++ -std=c++17 ../src/Cpp_shift.cpp -o Cpp_shift -Wall
clang++ -std=c++17 ../src/Cpp_shift.cpp -o Cpp_shift -Wall

在这两种情况下,我都得到了预期的 320 作为输出 (5 * 2 ^ 6)

有人可以解释为什么我会收到此警告吗?我忽略了什么吗?我还阅读了this 相关问题,但它没有回答我的问题。

编辑:所有其他变体 ++i &lt;&lt; ii &lt;&lt; ++ii &lt;&lt; i++ 都会产生相同的警告。

edit2:(i &lt;&lt; ++i) 导致 clang(正确)320 和 gcc(错误)384。如果++ 位于E2,gcc 似乎会给出错误的结果,(i &lt;&lt; i++) 也会给出错误的结果。

【问题讨论】:

  • 看起来诊断是由使用旧规则的逻辑创建的。我不确定何时引入&lt;&lt; 的排序,但可能直到 C++14 或 C++17 才引入。因为它显然是一个错误,理想情况下应该报告。
  • @KorelK 当我删除 -Wall 时,对于(i &lt;&lt; ++i),我仍然得到与 gcc 相同的错误结果。在没有-Wall 的情况下,clang 也会发出警告。
  • @xaxxon gcc 给 320 没有-fsanitize=undefined 和 160 有它
  • C++17 排序还没有完全被 GCC 实现。具有赋值运算符的 GCC 中相同性质的问题:stackoverflow.com/questions/51511102/…

标签: c++ language-lawyer c++17 sequence-points


【解决方案1】:

标准中明确了移位运算符的操作数的求值顺序。

n4659 - §8.8 (p4):

表达式E1在表达式E2之前排序。

表达式i++ &lt;&lt; i 中没有未定义的行为,它定义明确。这是ClangGCC 中的一个错误。

【讨论】:

  • 明确地说:质量差诊断中的错误,不一定是不合格中的错误。在诊断更新之前,实际的运行时行为可能已经修复以符合 C++17。
  • @hvd;现在 OP 更新了问题,我敢打赌这是 GCC 中的一个错误。
  • 有趣。 GCC 自己在 C++ Standards Support in GCC 上声称新行为是在 GCC 7 中实现的。
  • 令人惊讶的是,对于这样一个从根本上易于测试的更改,他们都错了——不仅仅是诊断,还有实际结果。
  • 主要问题下的cmets中的例子表明g++实际上是错误地实现了排序,这不仅仅是一个虚假的警告
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-12
  • 2017-02-04
  • 2017-03-12
  • 1970-01-01
  • 2022-11-17
相关资源
最近更新 更多