意外的评估顺序(编译器错误?)

时间:2011-03-07 00:40:20

标签: c++ gcc compiler-construction operator-precedence

  

可能重复:
  Undefined Behavior and Sequence Points

我不确定这是否是一个gcc bug,所以我会问:

unsigned int n = 0;
std::cout << n++ << n << ++n;

gcc给出了非常奇怪的结果: “122”,AFAICT是不可能的。因为&lt;&lt;是左关联的,它应该与:

相同
operator<<(operator<<(operator<<(std::cout, n++), n), ++n)

并且因为在评估参数之前和之后存在一个序列点,所以n在两个序列点之间永远不会被修改两次(甚至访问) - 因此它不应该是未定义的行为,只是未指定的评估顺序。

所以AFAICT的有效结果将是: 111 012 002 101

,没有别的

3 个答案:

答案 0 :(得分:9)

在评估参数和调用函数之间有一个序列点。在评估不同的参数之间没有序列点。

让我们看看最外面的函数调用:

operator<<(operator<<(operator<<(std::cout, n++), n), ++n)

参数是

  • operator<<(operator<<(std::cout, n++), n)

  • ++n

未指明首先评估哪些。还允许在评估第二个参数时部分评估第一个参数。

从标准,[intro.execution]部分(3225草案的措辞):

  
      
  • 如果 A 之前没有排序    B B A 之前未排序,然后 A B < EM>未测序。 [注意:执行未经检测的   评估可以重叠。 - 结束记录]

  •   
  • 除非另有说明,否则评估个体操作员的操作数和个体的子表达式   表达式没有排序。 [注意:在执行期间多次计算的表达式中   一个程序,对其子表达式的无序和不确定顺序的评估不一定​​是   在不同的评估中始终如一地进行。 - end note ]一个操作数的值计算   在运算符结果的值计算之前对运算符进行排序。如果对标量有副作用   对于相同标量对象的另一个副作用或值计算,对象未被排序   使用相同标量对象的值,行为未定义。

  •   

因为你有多个对同一个标量对象产生副作用的操作,这些操作相互之间没有顺序,你就处于未定义行为的领域,甚至999也是允许的输出。

答案 1 :(得分:4)

编译器错误的第一条规则:它可能不是编译器错误,而是您的误解。在同一语句中使用后缀和前缀运算符会导致未定义的行为。尝试使用-Wall选项为您提供更多警告,并向您展示代码中潜在的陷阱。

让我们看看当我们要求test.cpp发出警告时,GCC 4.2.1会告诉我们什么:

#include <iostream>

int main() {
    unsigned int n = 0;
    std::cout << n++ << n << ++n << std::endl;
    return 0;
}

编译时:

$ g++ -Wall test.cpp -o test
test.cpp: In function ‘int main()’:
test.cpp:5: warning: operation on ‘n’ may be undefined

答案 2 :(得分:-3)

你的代码是一个例子,说明为什么有些书中有经验的程序员不喜欢那个(++, - )运算符重载,甚至其他语言(ruby)都没有实现++或 - 。

相关问题