我有以下代码。
int x=80;
int &y=x;
x++;
cout<<x<<" "<<--y;
输出结果是80 80.我不明白怎么做。我认为x的输出是81,尽管我对y一无所知。参数变量如何受减量运算符的影响。有人可以解释一下吗?
答案 0 :(得分:19)
表达式评估为:
((cout << x) << " ") << --y;
在表达式的左侧和右侧的评估之间没有序列点(或排序),编译器可以输出评估--y
的代码作为第一步。
由于y
是对x
的引用,因此这实际上是未定义的行为,因为您在同一表达式中读取和写入x
而没有插入序列点。< / p>
答案 1 :(得分:6)
关于重定向运算符<<
的一个令人讨厌的事情是它们直观地传达了一个确实不存在的“顺序计算”的缺陷。
写作时
std::cout << f() << g() << std::endl;
输出将首先显示f()
的结果,然后显示g()
的结果,但实际调用g()
可能会在调用之前发生f()
。
它甚至比这更糟糕......并不是序列不可预测,但确实序列的概念无效。在
std::cout << f(g()) << h(i()) << std::endl;
例如合法的是,被调用的第一个函数是g()
,后跟i()
,后跟h()
,最后是f()
。甚至不能保证所有调用的顺序都是相同的(不是因为编译器制造商喜欢取笑你,而是因为代码可以内联,如果包含的函数在不同的上下文中内联,编译器可能会决定不同的顺序)。
保证评估顺序中序列的唯一C ++运算符是:
&&
:首先评估左侧,仅当结果为“true”时评估右侧||
:首先评估左侧,仅当结果为“false”时评估右侧?:
:首先评估条件,然后仅评估第二个或第三个操作数,
:逗号运算符...计算左侧,删除值,然后计算并返回右侧。注意:函数参数之间的逗号不是逗号运算符,也不会强制执行评估顺序。此外,此guaratee仅对预定义的运算符有效。如果您在班级中重载&&
,||
或,
,则他们只是普通的运营商,对评估顺序没有任何特殊限制。
任何其他运营商都不会对评估订单施加任何限制,这包括<<
,即使使用类型会让您想到这一点。
答案 2 :(得分:1)
这是未定义的行为,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
答案 3 :(得分:0)
x++
增加 x 并生成x的原始值作为表达式结果。
特别是,对于x ++, 没有为x的原始值的增量和生成隐含的时间顺序。 编译器可以自由地发出生成x的原始值,例如它可能存在于某个寄存器中,并将增量延迟到表达式结束(下一个序列点)。虽然x++
似乎将 x 增加到 81 ,但直到打印才会执行此操作。根据{{1}},它会获得递增的值(81)并在打印之前递减它,因为它是前缀运算符。