C++ C+中的复合操作评估+;

C++ C+中的复合操作评估+;,c++,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; } #包括 内部和外部(内部和内部) { 看跌期权(“这是f”); return++i; } int main() { int x=5;

当我执行以下代码时

#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;
}
#包括
内部和外部(内部和内部)
{
看跌期权(“这是f”);
return++i;
}
int main()
{
int x=5;
printf(“%d”,f(x)=f(x)+1);
返回0;
}

我得到的输出是8。我无法理解这是怎么发生的。有人能给我一个理由吗?

函数参数
i
是对
intx
的引用。 所以,
++i
实际上是在增加
x

f(x)
调用两次,初始值为
x=5
,这将使
x
等于7。
但在
printf
处添加了1,使最终值打印为8。

函数参数
i
是对
int x
的引用。 所以,
++i
实际上是在增加
x

f(x)
调用两次,初始值为
x=5
,这将使
x
等于7。
但在
printf
处添加了1,使最终值打印为8。

看看这行代码是如何计算的:

printf("%d",f(x)=f(x)+1);
第1步: x的初始化 -->x==5

第二步: f的第一次调用(等号的右侧) -->x==6

第三步: 添加1 -->x==7

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


编辑(请参阅注释以获得对Matt更深入的了解和thx):

看看这行代码是如何计算的:

printf("%d",f(x)=f(x)+1);
第1步: x的初始化 -->x==5

第二步: f的第一次调用(等号的右侧) -->x==6

第三步: 添加1 -->x==7

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


编辑(有关Matt的更深入了解,请参阅注释):

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

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

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

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

未指定对
f(x)
的两个调用中的哪一个首先发生;如果首先调用了右侧的函数,则无法确定该函数的prvalue转换是在调用左侧的
f(x)
之前还是之后进行的。但所有这些都发生在任务之前

一个有效订单是:

  • lhs f(x)
  • rhs f(x)
  • 右值转换
导致
i=7+1

或者可以是:

  • rhs f(x)
  • 右值转换
  • lhs f(x)
导致
i=6+1

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

参考文献: [执行简介]#15

除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的求值是不排序的

[expr.ass]#1

在所有情况下,赋值都是在右操作数和左操作数的值计算之后、赋值表达式的值计算之前排序的

在本引文中,“赋值表达式的值计算”是指如果该表达式是较大表达式的子表达式,则该表达式所取的值,例如
bar=(foo(x)=foo(x)+1)


此代码将允许您检查编译器使用的顺序。我插入了
,该条未经修改地传递其值

#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;
}
输出:


未指定对
f(x)
的两个调用中的哪一个首先发生;如果首先调用了右侧的函数,则无法确定该函数的prvalue转换是在调用左侧的
f(x)
之前还是之后进行的。但所有这些都发生在任务之前

一个有效订单是:

  • lhs f(x)
  • rhs f(x)
  • 右值转换
导致
i=7+1

或者可以是:

  • rhs f(x)
  • 右值转换
  • lhs f(x)
导致
i=6+1

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

参考文献: [执行简介]#15

除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的求值是不排序的

[expr.ass]#1

在所有情况下,赋值都是在右操作数和左操作数的值计算之后、赋值表达式的值计算之前排序的

在本引文中,“赋值表达式的值计算”是指如果该表达式是较大表达式的子表达式,则该表达式所取的值,例如
bar=(foo(x)=foo(x)+1)


此代码将允许您检查编译器使用的顺序。我插入了
,该条未经修改地传递其值

#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;
}
输出:

#包括
内部和外部(内部和内部)
{
看跌期权(“这是f”);
return++i;
}
int main()
{
int x=5;
//f(x)=f(x)+1等于
int&tmp_x=f(x);//x=6
inttmp=f(x)+1;//x=7,tmp=8
tmp_x=tmp;//x=8
printf(“%d”,tmp_x);
返回0;
}
#包括
内部和外部(内部和内部)
{
看跌期权(“这是f”);
return++i;
}
int main()
{
int x=5;
//f(x)=f(x)+1等于
int&tmp_x=f(x);//x=6
inttmp=f(x)+1;//x=7,tmp=8
tmp_x=tmp;//x=8
printf(“%d”,tmp_x);
返回0;
}
f(x)
增加1,因此,您可以简单地说
+1
。现在
x=5
f(x)=f(x)+1
相当于
x=(5+1)+1
,然后
x+=1
,因此
x
的最终值为8。因为基本上,
x=1+(5+1)+1
f(x)
增加1,所以您可以