大家好,在下面的代码中,第二个表达式后面的d的结果应该是什么?
int d = 1;
d += d++;
之后会假设 d 为 3,但一元增量 d++ 似乎没有生效,并且 d 保留值 2。
这个bug有名字吗?其他支持一元增量的编译器(如 C#)是否存在?
大家好,在下面的代码中,第二个表达式后面的d的结果应该是什么?
int d = 1;
d += d++;
之后会假设 d 为 3,但一元增量 d++ 似乎没有生效,并且 d 保留值 2。
这个bug有名字吗?其他支持一元增量的编译器(如 C#)是否存在?
这不是一个错误,它的行为完全符合预期。
+= 运算符扩展为:
d = d + d++;
这意味着当将结果分配回变量时,++ 运算符导致的更改将被覆盖。
如果你看一下生成的 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 的和。
(上面的代码来自发布模式构建)
如果以这种方式重写代码,它将设置 d 的值为 3:
int d = 1;
d += ++d;
查看++ Operator文档,了解您的示例为何如此行事。
摘抄:
第二种形式是后缀递增操作。操作的结果是操作数在递增之前的值。
正如@Guffa 指出的那样,这不是错误,只是您的后缀增量操作的结果d
被+=
操作覆盖。
我经常收到关于 ++ 运算符被“损坏”的问题;几乎总是因为提出问题的人习惯了它在某些行为++没有明确定义的语言中的工作方式,比如C++。这是我最近写的一篇关于这种情况的文章:
http://blogs.msdn.com/ericlippert/archive/2009/08/10/precedence-vs-order-redux.aspx
你试过++d吗?d++ 不是在之后评估吗?
我认为的行为d++
不同于++d
,尽管存储的最终结果d
是相同的。
愚蠢的代码是不可预测的。我可以推荐吗
d += 2;
d++ 和 ++d 是不同的。也称为“选择没有损坏” 。
...这就是为什么我发现后/前递增/递减运算符在与其他运算符一起使用时高度不可读的一个示例。您描述的行为是正确的,但很难推理,导致误解和错误。
即使它更冗长,我也会将其重写为:
int d = 1;
d += d;
++d;
请注意使用前增量运算符而不是后增量,以便编译器认为它不需要保留旧值的副本。