我不确定这是否是一个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
,没有别的
答案 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)都没有实现++或 - 。