【问题标题】:C# Compiler Behavior Question?C# 编译器行为问题?
【发布时间】:2010-12-06 02:09:14
【问题描述】:

大家好,在下面的代码中,第二个表达式后面的d的结果应该是什么?

        int d = 1;
        d += d++;

之后会假设 d 为 3,但一元增量 d++ 似乎没有生效,并且 d 保留了 2 的值。

这个错误有名字吗?其他支持一元增量的编译器(如 C#)是否存在?

【问题讨论】:

  • 问为什么,或者即使编译器是错误的,这通常是一个错误的问题。询问您的特殊情况发生的原因可能是正确的问题。今天的 C# 编译器只经过了少量的严格测试,通常值得怀疑。
  • 不确定这是否是一个错误,我原以为答案也是 3,但如果在后缀 ++ 处评估,d 的值是 1,所以答案是 2,或者是运算符在 ?
  • @Kenny Nah,只是一个“?”无法弥补达科他州的大卫认为这至少有 50% 的可能性可能是计算机错误而不是他缺乏理解这一事实。
  • d = (2*d)+1 即使错误不存在也不会令人困惑。
  • 编写此类代码的任何开发人员都存在错误。

标签: c# compiler-construction increment unary-operator


【解决方案1】:

这不是错误,它的行为完全符合预期。

+= 运算符扩展为:

d = d + d++;

这意味着当将结果分配回变量时,++运算符导致的更改将被覆盖。

【讨论】:

  • 完整的扩展是:temp = d + d; d = d + 1; d = 温度;
  • 我认为他的问题在于 d++,而不是 +=。
【解决方案2】:

如果您查看生成的 IL,您会明白为什么结果是 2 而不是 3。

IL_0000:  ldc.i4.1  // load constant 1 on evaluation stack
IL_0001:  stloc.0   // pop and store value in local 0
IL_0002:  ldloc.0   // load value of local 0 on evaluation stack
IL_0003:  ldloc.0   // repeat, stack is now 1, 1
IL_0004:  dup       // duplicate topmost value on evaluation stack, 
                    // i.e. stack is now 1, 1, 1
IL_0005:  ldc.i4.1  // load constant 1 on evaluation stack
IL_0006:  add       // add two topmost values on stack, 
                    // i.e. 1 and 1 and push result on stack
IL_0007:  stloc.0   // pop and store this value in local 0
IL_0008:  add       // add the two remaining values on the stack
                    // which again happens to be 1 and 1 and push result to stack
IL_0009:  stloc.0   // pop and store this value in local 0

换句话说:存储的最终值是 1 和 1 的和。

(以上代码来自发布模式构建)

【讨论】:

    【解决方案3】:

    如果你用这种方式重写你的代码,它会将 d 的值设置为 3:

    int d = 1;
    d += ++d;
    

    请查看++ Operator 文档,了解您的示例为何如此行事。
    摘录:

    第二种形式是后缀增量 手术。操作结果 是它之前的操作数的值 已递增。

    正如@Guffa 所指出的,这不是错误,只是d 中的后缀递增操作的结果被+= 操作覆盖。

    【讨论】:

    • 我觉得你的甜甜圈有个洞。不同的问题?
    • 如果有人重写他们的代码看起来像这样,我会立即将他们从团队中解雇。 2 次罢工。
    【解决方案4】:

    我经常收到关于 ++ 运算符被“损坏”的问题;几乎总是因为提出问题的人习惯了它在某些行为++没有明确定义的语言中的工作方式,比如C++。这是我最近写的一篇关于这种情况的文章:

    http://blogs.msdn.com/ericlippert/archive/2009/08/10/precedence-vs-order-redux.aspx

    【讨论】:

      【解决方案5】:

      你试过++d吗? d++ 不是经过评估吗?

      【讨论】:

      • 小心。在what之后评估,究竟是什么? ++d 和 d++ 之间的主要区别在于,表达式结果的计算发生在将递增结果存储到变量之前或之后。认为后缀表达式作为一个整体的求值以某种方式比嵌入它的表达式的其他部分“晚”发生是一个常见的错误,但这是一个神话。
      • 对。如果在评估整个表达式之后应用 ++,那么我们期望看到 3.
      【解决方案6】:

      我认为d++ 的行为与++d 不同,尽管存储在d 中的最终结果是相同的。

      【讨论】:

        【解决方案7】:

        愚蠢的代码是不可预测的。我可以推荐吗

        d += 2;
        

        【讨论】:

        • 这根本不是不可预测的。语言规范非常清楚这段代码应该做什么。我同意这很愚蠢。
        • 不是“不可预测”,但绝对是“不必要地难以预测”,我认为这已经足够接近了。 :)
        【解决方案8】:

        d++ 和 ++d 是不同的。也称为“Select Isn't Broken.

        【讨论】:

          【解决方案9】:

          ...这就是为什么我发现后/前递增/递减运算符在与其他运算符一起使用时高度不可读的原因的一个例子。您描述的行为是正确的,但很难推理,导致误解和错误。

          即使它更冗长,我也会将其重写为:

          int d = 1;
          d += d;
          ++d;
          

          注意使用前置增量操作符而不是后置增量,这样编译器就不会认为它需要保留旧值的副本。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-05-17
            • 2010-11-26
            • 1970-01-01
            • 1970-01-01
            • 2014-02-22
            • 2014-11-05
            相关资源
            最近更新 更多