这个表达的结果不是我学到的

result of this expression is not what i learned

提问人:Guest Man 提问时间:11/13/2023 最后编辑:Guest Man 更新时间:11/13/2023 访问量:102

问:

在下面的代码中,结果为 -6。为什么?

`    int x = 5;
    int y = 3;
    int result = x++ - (--y + ++x) - y--;`

我认为首先,在括号内评估,然后在括号外按从左到右的顺序进行评估,但这样,结果就不会是-6。 在我看来,这是顺序:

  1. ++x
  2. --y
  3. X++的
  4. G-S
  5. 第一个 - 从左起
    • 在表达过程中
  6. 最后 - 从左起

在数字 1 中,值为 6,x 为 6

在数字 2 中,值为 2,y 为 2

在数字 3 中,值为 6,x 为 7

在数字 4 中,值为 2,y 为 1

在数字 5,6,7 中,表达式为 6 - 8 - 2 = -4,不等于 -6;

在运算符优先级和运算符关联性方面

C# 表达式 运算符优先级 关联性

评论

0赞 Charlieface 11/13/2023
“我认为一开始,括号内评估”你为什么这么认为?为什么 1 和 2 似乎是互换的?
0赞 Auditive 11/13/2023
C# 中前后增量的副本
1赞 Flydog57 11/13/2023
以下是简明扼要地解释的规则: ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order
1赞 Auditive 11/13/2023
x++ - (--y + ++x) - y--对于您输入的内容,并将评估为 .括号不优先考虑“以哪个顺序做++--”,而是优先考虑“按哪个顺序计算结果”。所以顺序看起来像“首先通过++/--获取所有结果值,然后在括号中计算值,然后从左边的第一个值中减去它,然后减去右边的值”。而不是“在括号中获取结果值并计算它们,然后计算左值并从中减去括号部分的结果,然后计算右值并减去它”。x = 5y = 35 - (2 + 7) - 2
1赞 Charlieface 11/13/2023
这只是意味着,当从左到右时,如果你遇到一个parens,你会把它作为一个整体来计算。并不是说你应该在做任何其他事情之前计算所有 paren。

答:

1赞 PajLe 11/13/2023 #1

引用 C# 规范(ECMA-334,第 6 版,2022 年 6 月,§11.4.1):

表达式中的操作数按从左到右的顺序计算。

这意味着你最初的假设是不正确的:“我认为首先,括号内评估了”。


在这种情况下,将首先进行评估;序列如下所示:x++

  1. x++被计算,返回 5,但在 x 中保存 6
  2. --y被计算,返回 2,并在 y 中保存 2
  3. ++x计算结果为 7(因为上一次操作为 6)x
  4. 括号中的内容被计算 (2 + 7) = 9
  5. 计算第一个减法:(从步骤 1 开始。 (从步骤 4 开始。=5-9-4
  6. y--得到评估,返回 2,但在 y 中保存 1
  7. 最终减法得到计算:(从步骤 5 开始。 (从步骤 6 开始。=-4-2-6

正如其中一条评论(优先级、关联性与顺序)中提到的,区分以下因素很重要:

  • 优先级规则描述当表达式混合使用不同类型的运算符时,应如何用括号括号括住带括号的表达式

  • 关联性规则描述当表达式具有一堆相同类型的运算符时,应如何用括号括起来的表达式

  • 计算规则的顺序描述表达式中每个操作数的计算顺序

评论

0赞 Guest Man 11/13/2023
感谢您的回复。那么什么是从左到右或从右到左的关联性?例如,我听说后增量/递减是从右到左,但递增/递减前是从左到右。此规则将在哪里适用?如果这是真的,++x 应该在 --y 之前计算。
0赞 PajLe 11/14/2023
从规范中可以看出: 当操作数发生在具有相同优先级的两个运算符之间时,运算符的关联性控制操作的执行顺序。 ++x 和 --y 都是一元运算。我们仍然可以谈论它们的关联性,但这可能会令人困惑。--x 和 ++x 保持关联,这意味着您将首先“评估”,然后 .x++ 的正确关联意味着您将首先“评估”,然后--x++x
0赞 PajLe 11/14/2023
对于您给出的示例,no 是因为这两个操作数之间的运算符是 ,并且是左关联的(除了赋值运算符和 null 合并运算符外,所有二进制运算符都是左关联的,这意味着运算是从左到右执行的。If this is true , ++x should evaluate before --y++)
0赞 Jeremy Lakeman 11/13/2023 #2
int result = x++ - (--y + ++x) - y--;

生成的 IL 大致相当于;

var t0 = x;
var t1 = t0 + 1;
x = t1;

var t2 = y;
var t3 = t2 - 1;
y = t3;

var t4 = x;
var t5 = t4 + 1;
x = t5;

var t6 = t3 + t5;
var t7 = t0 - t6;

var t8 = y;
var t9 = t8 - 1;
y = t9;

var t10 = t7 - t8;
int result = t10;

您提供的值从左到右计算。当左手值和右手值都可用时,将计算二进制运算。括号强制将哪些值绑定到每个二进制操作的左手和右手。