14

我有以下代码。

    int x=80;
    int &y=x;
    x++;
    cout<<x<<" "<<--y;

输出结果是 80 80。我不明白怎么做。我认为 x 的输出将是 81,尽管我对 y 一无所知。减量运算符如何影响引用变量。有人可以解释一下吗?

4

4 回答 4

19

表达式被评估为:

((cout << x) << " ") << --y;

在表达式的左侧和右侧的求值之间没有序列点(或排序),编译器可以输出--y作为第一步求值的代码。

由于y是对x此处的引用,因此这实际上是未定义的行为,因为您x在同一个表达式中读取和写入,而没有干预序列点。

于 2013-08-25T07:37:06.697 回答
6

关于重定向运算符的一个讨厌的事情<<是,它们直观地传达了一种确实不存在的“顺序计算”。

当你写

std::cout << f() << g() << std::endl;

输出将首先显示结果,f()然后显示结果g(),但实际调用g()可能发生在调用之前f()

它甚至比这更糟……不是序列不可预测,而是序列的概念确实是无效的。在

std::cout << f(g()) << h(i()) << std::endl;

例如,被调用的第一个函数是合法的g(),然后是i(),然后是h(),最后是f()。甚至不能保证所有调用的顺序都是相同的(不是因为编译器制造商喜欢取笑你,而是因为代码可以内联,如果包含函数在不同的上下文中内联,编译器可能会决定不同的顺序)。

保证评估顺序中的序列的唯一 C++ 运算符是:

  1. &&:首先评估左侧,只有当结果为“真”时才评估右侧
  2. ||:首先评估左侧,只有当结果为“假”时才评估右侧
  3. ?:: 首先计算条件,然后只计算第二个或第三个操作数
  4. ,:逗号运算符...计算左侧,删除值,然后计算并返回右侧。注意:函数参数之间的逗号不是逗号运算符,并且没有施加评估顺序。

此外,此保证仅对预定义的运算符有效。如果您重载&&||或者,在您的班级中,它们只是普通运算符,对评估顺序没有任何特殊限制。

任何其他运算符都不会对评估顺序施加任何限制,这包括<<即使使用方式会欺骗您思考。

于 2013-08-25T08:20:57.677 回答
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
于 2013-08-25T07:57:27.803 回答
0
x++

递增x并生成 x 的原始值作为表达式结果。

特别是,对于 x++,对于 x 的原始值的增量和产生没有隐含的时间顺序。编译器可以自由地发出产生 x 的原始值的机器代码,例如它可能存在于某个寄存器中,并且延迟增量直到表达式结束(下一个序列点)。尽管x++似乎将x增加到81,但直到打印才这样做。根据--y,它在打印它之前获取递增的值(81)并递减它,因为它是前缀运算符。

于 2013-08-25T08:05:28.293 回答