意外的 post-赋值中的增量行为

Unexpected post-increment behavior in assignment

你能帮我理解为什么变量 a 在第一种情况下没有递增,而在第二种情况下却递增吗?

案例一:

int a = 10;            
a = a++;
Console.WriteLine(a); //prints 10

案例二:

int a = 10;                        
int c = a++;
Console.WriteLine(a); //prints 11

我已经回答了其他类似的问题,但找不到任何细节。

更新 1: 我认为程序流程如何

案例一:

1. 'a' is assigned 10
2. 'a' is assigned 10 before increment happens
3. 'a' is incremented by 1 (Why doesn't this step affect the final value of 'a'?)
4. 'a' is printed --> 10

案例二:

1. 'a' is assigned 10
2. 'c' is assigned 10 before 'a' is incremented
3. 'a' is incremented by 1 (Why does the increment of 'a' work here?)
4. 'a' is printed --> 11

更新2:感谢大家的回答,我想我已经明白了,如果我错了请指正。

案例一:

1. `a` is assigned 10
2. Compiler evaluates `a++`, stores old value 10 and new value 11 as well. Since it's a post increment operation, assigns the old value to `a`. What i thought was, compiler would assign the old value 10 first and evaluate the `++` operation later. This is where i was wrong, compiler evaluates the RHS beforehand and assigns the value based on the operator.
4. 'a' is printed --> 10

案例二:

1. `a` is assigned 10
2. Compiler evaluates `a++`, stores old value 10 and new value 11 as well. Since it's a post increment operation, assigns the old value to `c` but value of `a` is preserved with `11`.
4. 'a' is printed --> 11

第一种情况a = a++是post-增量。其中表示将 1 添加到 a,但 return 是 a 的先前值,然后将先前的结果存储回 a。这基本上是空操作。

如果是预增,a = ++a,那么a就是11。

你应该在情况 2 中打印出 c。 post incement 运算符的结果始终是增量之前的值。因此,首先将值 10 返回,然后将其递增到 11,然后将运算符结果 (10) 分配给左操作数。

这里没有任何人在评论中描述的未定义行为。

这是明确定义的行为。要了解发生了什么,您必须首先了解 pre increment and post increment 运算符的工作原理。

案例一:

a++(post increment) 将递增 a 的值并将其存储在 a 然后 returns 递增之前的值.

所以在执行a++;后,a的值将是11,但运算符将return 10.

然后a = a++;赋值部分变成a = 10;.

案例2:

同样,a++; 会将 a 的值增加到 11 并且 return 是先前的值 (10)。将分配给 cc 将是 10,但 a 将是 11,因为在这种情况下您不会覆盖 a 的值。

您的 Case1 等于:

int a = 10;
int temp = a;//10
a = a + 1;  //11
a = temp;   //10
Console.WriteLine(a);//10

Case2等于:

int a = 10;
int temp = a;//10
a = a + 1;   //11
int c = temp;//10
Console.WriteLine(a);//11

我希望现在你应该清楚为什么你看到你所看到的。

说清楚,++a和a++是有区别的

两者的结果是一样的,就是把a加1,但是过程有点不同,只有赋值给另一个才能看出来多变的。

这是 prepost 增量之间的区别,您可能会寻找

案例一

 int a,b;
 a = 10;
 b = a++; //Here b is assigned by a post-incremented a, therefore b value is still 10

案例二

 int a,b;
 a = 10;
 b = ++a; //Here b is assigned by a pre-incremented a, b value is now 11

取自http://en.wikipedia.org/wiki/Increment_and_decrement_operators

更新

回复此问题

int a = 10;
a = a++;

过程如下:

1. variable 'a' with data type integer is created

2. variable 'a' value is assigned with 10

3. check the availability and the data type correctness of the right side. This means all operation on the right side (increment 'a') is being executed. 'a' is now 11

4. assign the post-incremented value to 'a', which is 10, 'a' is now 10

对我来说,了解某些行为的最佳方式是检查生成的 IL。在你的第一种情况下是

IL_0001:  ldc.i4.s    0A // stack: 10
IL_0003:  stloc.0     // a = 10, stack: empty
IL_0004:  ldloc.0     // stack: 10
IL_0005:  dup         // stack: 10, 10
IL_0006:  ldc.i4.1    // stack: 10, 10, 1
IL_0007:  add         // stack: 10, 11
IL_0008:  stloc.0     // a = 11, stack: 10
IL_0009:  stloc.0     // a = 10, stack: empty
IL_000A:  ldloc.0     // stack: 10
IL_000B:  call        System.Console.WriteLine

您可以看到原始值仍然挂在堆栈上,因此创建的 11 最后被覆盖了。

让我试着用通俗易懂的语言解释一下。

当您为变量赋值时 (a = a++),赋值的整个右侧首先被计算以保证正确的值,就是这样。所以没有什么比你得到 10 更重要的是,当你执行下一行时,应用程序继续并增加值。

现在,将 post-increment 想象成某人,他首先递增一个值,但给了你他的世界,你将从表达式中取回原始值。现在你应该明白为什么 11 被覆盖了。增量在前,最后,您将获得承诺的原始值(正如 IL 所证明的那样)。

我不认为这是未定义的行为,因为在第一种情况下:

int a = 10;            
a = a++;
Console.WriteLine(a); //prints 10

a的值是递增动作前的值,也就是说如果我们简化a = a++,那么:

a = a ; // `a` has `10`

a++; // `a` has `11`

只有这样 a 才具有值 11

第二种情况:

int a = 10;                        
int c = a++;
Console.WriteLine(a); //prints 11

现在c有值10因为赋值操作使得左边的值在递增动作之前得到变量(右边)的值,并且只然后右侧的值增加 1 .

这不是未定义的行为,也不是错误。来自 MSDN Documentation:

The increment operator (++) increments its operand by 1. 
The increment operator can appear before or after its operand.
The first form is a prefix increment operation. The result of the operation is the value of the operand after it has been incremented.
The second form is a postfix increment operation. The result of the operation is the value of the operand before it has been incremented.

从字面上看,MSDN 告诉您,如果您使用此语法(后缀):

a = a++;

则运算结果会把a赋值给a然后递增。但是,由于赋值操作已经发生,您正在丢失增量的结果。

像这样使用它(前缀):

a = ++a;

这将首先增加 a,然后将增加的值分配给 a

编辑

我将尝试对此进行分解,希望您能更好地理解。

首先,要知道 ++ 总是 returns 一个值。如果您使用前缀版本(例如 ++a),它 returns 的值是 a+1。如果您使用后缀版本(例如 a++),它 returns 在增量发生之前 a 的值。

当你执行这段代码时:

int a = 10;
a = a++;

您是在告诉编译器在递增之前将 a 的值赋给 a。因此执行后 a 等于 1011 的增量值在 "nether" 中丢失。请注意,您没有将 11 分配给 a。您在增量之前分配旧值,这就是为什么您得到 10.

输出的原因

当你执行这段代码时:

int a = 10;
int b = a++;

最后一行执行后,它递增 a 等于 11 并将 10 分配给 'b'。由于您要分配给不同的变量,因此 a 不会像第一个示例中那样被其原始值 10 覆盖。

为了使它更加直观,请看这里:

a = a++;
    ^ a is increased to 11, but the postfix increment returns the old value (10)

这一行实际上变成了:

a = 10;

int b = a++;
        ^ a is increased to 11, but b gets assigned a's old value

这一行实际上变成了:

int b = 10;
a = a + 1;

这样就清除了吗?