gpt4 book ai didi

c# - "k += c += k += c;"中是否有内联运算符的解释?

转载 作者:IT王子 更新时间:2023-10-29 03:37:44 25 4
gpt4 key购买 nike

下面操作结果的解释是什么?

k += c += k += c;

我试图理解以下代码的输出结果:

int k = 10;
int c = 30;
k += c += k += c;
//k=80 instead of 110
//c=70

目前我正在努力理解为什么“k”的结果是 80。为什么分配 k=40 不起作用(实际上 Visual Studio 告诉我该值没有在其他地方使用)?

为什么 k 是 80 而不是 110?

如果我将操作拆分为:

k+=c;
c+=k;
k+=c;

结果是 k=110。

我试图浏览 CIL , 但我对生成的 CIL 的解释不是很深刻,无法获得一些细节:

 // [11 13 - 11 24]
IL_0001: ldc.i4.s 10
IL_0003: stloc.0 // k

// [12 13 - 12 24]
IL_0004: ldc.i4.s 30
IL_0006: stloc.1 // c

// [13 13 - 13 30]
IL_0007: ldloc.0 // k expect to be 10
IL_0008: ldloc.1 // c
IL_0009: ldloc.0 // k why do we need the second load?
IL_000a: ldloc.1 // c
IL_000b: add // I expect it to be 40
IL_000c: dup // What for?
IL_000d: stloc.0 // k - expected to be 40
IL_000e: add
IL_000f: dup // I presume the "magic" happens here
IL_0010: stloc.1 // c = 70
IL_0011: add
IL_0012: stloc.0 // k = 80??????

最佳答案

a op= b;这样的操作等同于a = a op b;。赋值可以用作语句或表达式,而作为表达式它会产生指定的值。你的陈述......

k += c += k += c;

...,因为赋值运算符是右结合的,也可以写成

k += (c += (k += c));

或(展开)

k =  k +  (c = c +  (k = k  + c));
10 → 30 → 10 → 30 // operand evaluation order is from left to right
| | ↓ ↓
| ↓ 40 ← 10 + 30 // operator evaluation
↓ 70 ← 30 + 40
80 ← 10 + 70

在整个评估过程中,使用相关变量的旧值。对于 k 的值尤其如此(请参阅我对下面的 IL 的评论和 link Wai Ha Lee 提供的)。因此,您得到的不是 70 + 40(k 的新值)= 110,而是 70 + 10(k 的旧值)= 80。

要点是(根据 C# spec)“表达式中的操作数是从左到右计算的”(操作数是变量 ck 在我们的例子中)。这与运算符优先级和结合性无关,在这种情况下,运算符优先级和结合性指示从右到左的执行顺序。 (请参阅本页对 Eric Lippert 的 answer 的评论)。


现在让我们看看 IL。 IL 假定一个基于堆栈的虚拟机,即它不使用寄存器。

IL_0007: ldloc.0      // k (is 10)
IL_0008: ldloc.1 // c (is 30)
IL_0009: ldloc.0 // k (is 10)
IL_000a: ldloc.1 // c (is 30)

堆栈现在看起来像这样(从左到右;堆栈顶部在右边)

10 30 10 30

IL_000b: add          // pops the 2 top (right) positions, adds them and pushes the sum back

10 30 40

IL_000c: dup

10 30 40 40

IL_000d: stloc.0      // k <-- 40

10 30 40

IL_000e: add

10 70

IL_000f: dup

10 70 70

IL_0010: stloc.1      // c <-- 70

10 70

IL_0011: add

80

IL_0012: stloc.0      // k <-- 80

请注意,IL_000c: dupIL_000d: STLoc.0,即对 k 的第一个赋值,可以优化掉。这可能是在将 IL 转换为机器代码时通过抖动对变量完成的。

另请注意,计算所需的所有值要么在进行任何赋值之前被压入堆栈,要么根据这些值计算得出。分配的值(由 STLoc)在此评估期间永远不会重复使用。 STLoc 弹出栈顶。


以下控制台测试的输出是(Release 模式开启优化)

evaluating k (10)
evaluating c (30)
evaluating k (10)
evaluating c (30)
40 assigned to k
70 assigned to c
80 assigned to k

private static int _k = 10;
public static int k
{
get { Console.WriteLine($"evaluating k ({_k})"); return _k; }
set { Console.WriteLine($"{value} assigned to k"); _k = value; }
}

private static int _c = 30;
public static int c
{
get { Console.WriteLine($"evaluating c ({_c})"); return _c; }
set { Console.WriteLine($"{value} assigned to c"); _c = value; }
}

public static void Test()
{
k += c += k += c;
}

关于c# - "k += c += k += c;"中是否有内联运算符的解释?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54674728/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com