C ++中的复合运算评估

时间:2014-07-17 06:50:21

标签: c++

当我执行以下代码时

#include <iostream>
int & f(int &i)
{
    puts("this is f");
    return ++i;
}

int main()
{
    int x = 5;
    printf("%d", f(x) = f(x) + 1);
    return 0;
}

我输出为8.我无法理解这是怎么回事。谁能给我一个理由呢?

5 个答案:

答案 0 :(得分:2)

了解如何评估这行代码:

printf("%d",f(x)=f(x)+1);

第1步: x的初始化 - &GT; x == 5

第2步: 第一次调用f(等号的右侧) - &GT; x == 6

第3步: 添加1 - &GT; x == 7

第4步: f的第二次调用(等号的左侧) - &GT; x == 8

编辑(请参阅评论以获得更深入的见解,并向马特致谢):

答案 1 :(得分:2)

未指明对f(x)的两次调用中的哪一次首先发生;如果右手边的那个被称为第一个,那么未指定是否在对左侧f(x)的呼叫之前或之后发生了它的prvalue转换。但所有这些都发生在任务之前。

一个有效的订单是:

  • lhs f(x)
  • rhs f(x)
  • 右值转换

会产生i = 7 + 1;

或者可能是:

  • rhs f(x)
  • 右值转换
  • lhs f(x)

会产生i = 6 + 1;

没有与++运算符相关的未定义行为,因为在每个函数调用之前和之后都有一个序列点。

参考文献: [intro.execution]#15

  

除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的评估是不确定的

[expr.ass]#1

  

在所有情况下,赋值在右和左操作数的值计算之后,以及赋值表达式的值计算之前进行排序。

在这个引用中,&#34;赋值表达式的值计算&#34;表示该表达式所具有的值,如果它是较大表达式的子表达式,例如, bar = ( foo(x) = foo(x) + 1 );


此代码将让您检查编译器正在使用的顺序。我插入了bar,它通过未修改的值传递其值。

#include <cstdio>
using namespace std;

int & f(int idx, int &i)
{
printf("this is f %s\n", idx ? "right" : "left");
return ++i;
}

int bar(int idx, int z) 
{
    printf("bar%d = %d\n", idx, z);
    return z;
}

int main()
{
    int x=5;
    f(0,x)= bar(0, bar(1, f(1,x)) + 1 );
    printf("final = %d\n",x);
    return 0;
}

我系统的输出:

this is f left
this is f right
bar1 = 7
bar0 = 8
final = 8

输出for Coliru

this is f right
bar1 = 6
bar0 = 7
this is f left
final = 7

答案 2 :(得分:1)

您使用参考参数。在f函数中修改变量x时,也可以在main函数中修改。

First x = 5
When you call f first time, x = 6
When you call f second time, x = 7
Finally, 7 + 1 = 8

答案 3 :(得分:0)

函数参数i是对int x的引用。 因此,++i实际上正在递增x

使用初始f(x)调用

x=5两次,这将使x等于7。 但是printf添加了1,最终值为8。

答案 4 :(得分:0)

#include <iostream>

int & f(int &i)
{
    puts("this is f");
    return ++i;
}

int main()
{
    int x=5;
    //f(x)=f(x)+1 equals to following
    int& tmp_x = f(x); //x=6
    int tmp = f(x)+1; //x = 7, tmp = 8
    tmp_x = tmp; //x=8
    printf("%d",tmp_x);
    return 0;
}