我有以下代码。
int x=80;
int &y=x;
x++;
cout<<x<<" "<<--y;
输出结果是 80 80。我不明白怎么做。我认为 x 的输出将是 81,尽管我对 y 一无所知。减量运算符如何影响引用变量。有人可以解释一下吗?
我有以下代码。
int x=80;
int &y=x;
x++;
cout<<x<<" "<<--y;
输出结果是 80 80。我不明白怎么做。我认为 x 的输出将是 81,尽管我对 y 一无所知。减量运算符如何影响引用变量。有人可以解释一下吗?
表达式被评估为:
((cout << x) << " ") << --y;
在表达式的左侧和右侧的求值之间没有序列点(或排序),编译器可以输出--y
作为第一步求值的代码。
由于y
是对x
此处的引用,因此这实际上是未定义的行为,因为您x
在同一个表达式中读取和写入,而没有干预序列点。
关于重定向运算符的一个讨厌的事情<<
是,它们直观地传达了一种确实不存在的“顺序计算”。
当你写
std::cout << f() << g() << std::endl;
输出将首先显示结果,f()
然后显示结果g()
,但实际调用g()
可能发生在调用之前f()
。
它甚至比这更糟……不是序列不可预测,而是序列的概念确实是无效的。在
std::cout << f(g()) << h(i()) << std::endl;
例如,被调用的第一个函数是合法的g()
,然后是i()
,然后是h()
,最后是f()
。甚至不能保证所有调用的顺序都是相同的(不是因为编译器制造商喜欢取笑你,而是因为代码可以内联,如果包含函数在不同的上下文中内联,编译器可能会决定不同的顺序)。
保证评估顺序中的序列的唯一 C++ 运算符是:
&&
:首先评估左侧,只有当结果为“真”时才评估右侧||
:首先评估左侧,只有当结果为“假”时才评估右侧?:
: 首先计算条件,然后只计算第二个或第三个操作数,
:逗号运算符...计算左侧,删除值,然后计算并返回右侧。注意:函数参数之间的逗号不是逗号运算符,并且没有施加评估顺序。此外,此保证仅对预定义的运算符有效。如果您重载&&
,||
或者,
在您的班级中,它们只是普通运算符,对评估顺序没有任何特殊限制。
任何其他运算符都不会对评估顺序施加任何限制,这包括<<
即使使用方式会欺骗您思考。
这是未定义的行为,C/C++ 标准没有定义参数被压入堆栈的方式,通常参数以相反的顺序被压入,例如这里:
func(1, 2)
将被评估为:
push 2
push 1
call func
所以在你的情况下,--y
在之前进行评估和推送x
。在这个例子中很清楚:
#include <iostream>
int a() { std::cout << "a" << std::endl ; return 1; }
int b() { std::cout << "b" << std::endl ; return 2; }
int main(void) {
std::cout << a() << " " << b() << std::endl;
return 0;
}
乍一看,它应该打印:
a
b
1 2
但它打印:
b
a
1 2
x++
递增x并生成 x 的原始值作为表达式结果。
特别是,对于 x++,对于 x 的原始值的增量和产生没有隐含的时间顺序。编译器可以自由地发出产生 x 的原始值的机器代码,例如它可能存在于某个寄存器中,并且延迟增量直到表达式结束(下一个序列点)。尽管x++
似乎将x增加到81,但直到打印才这样做。根据--y
,它在打印它之前获取递增的值(81)并递减它,因为它是前缀运算符。