2

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

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

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

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

4

9 回答 9

33

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

+= 运算符扩展为:

d = d + d++;

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

于 2009-10-12T18:53:43.717 回答
16

如果你看一下生成的 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 的和。

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

于 2009-10-12T19:11:43.960 回答
12

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

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

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

第二种形式是后缀递增操作。操作的结果是操作数在递增之前的值。

正如@Guffa 指出的那样,这不是错误,只是您的后缀增量操作的结果d+=操作覆盖。

于 2009-10-12T18:52:41.487 回答
4

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

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

于 2009-10-12T19:28:55.393 回答
2

你试过++d吗?d++ 不是在之后评估吗?

于 2009-10-12T18:53:14.840 回答
2

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

于 2009-10-12T18:53:55.137 回答
1

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

d += 2;
于 2009-10-12T18:56:03.477 回答
1

d++ 和 ++d 是不同的。也称为“选择没有损坏” 。

于 2009-10-12T18:58:30.663 回答
1

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

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

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

请注意使用前增量运算符而不是后增量,以便编译器认为它不需要保留旧值的副本。

于 2009-10-12T19:01:43.497 回答