序列点 - 这个 gcc 警告是一个错误吗?

Ofe*_*lon 7 c++ language-lawyer c++17

拿这个玩具程序:

int main() 
{
  int a = 1;
  a = ++a ;
}
Run Code Online (Sandbox Code Playgroud)

在 gcc 9.3(甚至主干)下编译-Wall -std=c++17输出:

<source>:4:5: warning: operation on 'a' may be undefined [-Wsequence-point]
    4 |   a = ++a ;
      |   ~~^~~~~
Run Code Online (Sandbox Code Playgroud)

我知道在过去这确实是一个问题,但是对同一 SO 问题不同答案指向 C++17 标准的一部分,该标准已修复以表明在赋值操作中,rhs 在实际任务:

8.18. ... 在所有情况下,赋值顺序在左右操作数的值计算之后,赋值表达式的值计算之前。

那么这个警告确实是假的还是我遗漏了什么?

Nat*_*ica 8

是的,这是一个错误。每[expr.ass]/1

赋值运算符 (=) 和复合赋值运算符都从右到左分组。所有都需要一个可修改的左值作为它们的左操作数,并返回一个引用左操作数的左值。如果左操作数是位域,则所有情况下的结果都是位域。在所有情况下,赋值顺序都在左右操作数的值计算之后,赋值表达式的值计算之前。右操作数排在左操作数之前。对于不确定顺序的函数调用,复合赋值的操作是单个评估。[?注:因此,函数调用不应干预左值到右值的转换以及与任何单个复合赋值运算符相关的副作用。?—?尾注?]

强调我的

现在在增量和赋值之间有一个序列点,并且代码具有明确定义的行为。他们的警告启发式需要更新以考虑到这个新功能。


wal*_*nut 5

正如另一个答案中已经提到的,代码表现良好,并且该消息对于 C++17 是误报,但我想补充一点,GCC 仍然有目的地对此发出警告。

GCC文档声明了有关-Wsequence-point警告标志(由 启用-Wall):

C++17 标准将在更多情况下定义操作数的求值顺序:特别是它要求赋值的右侧先于左侧求值,因此上述示例不再是未定义的。但此选项仍会警告它们,以帮助人们避免编写在 C 和早期版本的 C++ 中未定义的代码。

因此,该程序旨在发出该警告。

  • 感谢您指出了这一点!它实际上看起来很像一个伪装成功能的错误。这个警告应该在 -std=C++17 上被消除,如果人们需要遵守早期的标准,他们可以编译它。“帮助人们避免旧标准中的 UB 代码”充其量是一个奇怪的设计目标。 (2认同)