赋值中出现意外的后增量行为

时间:2015-01-17 05:51:17

标签: c# expression

请问您能帮助我理解为什么变量a在第一种情况下没有增加但是在第二种情况下会增加?

案例1:

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

案例2:

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

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

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

案例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

案例2:

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:

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

案例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 `c` but value of `a` is preserved with `11`.
4. 'a' is printed --> 11

7 个答案:

答案 0 :(得分:6)

第一种情况a = a++是后增量。这表示将{1}添加到a,但返回先前的a值,然后将之前的结果存储回a。这基本上是一种无操作。

如果是预增量a = ++a,那么a将为11.

答案 1 :(得分:5)

对我而言,理解某些行为的最佳方法是检查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,应用程序继续执行下一行时增加值。

现在,想象一下后增量作为某人,他先增加一个值,但给了他的世界,你将从表达式中获得原始值。现在你应该明白为什么11被覆盖了。增量先行,最后,你得到承诺原始价值(正如IL证明的那样)。

答案 2 :(得分:3)

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

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

<强>情况1:

a++(增量后)将增加a的值并将其存储在a中,然后在值递增之前返回该值。

因此,在执行a++;后,a的值将为11,但运算符将返回10

然后a = a++;分配部分变为a = 10;

<强>情况2:

Sameway a++;会将a的值增加到11并返回之前的值(10)。将分配给cc为10,a为11,因为在这种情况下,您不会覆盖a的值。

您的案例1 等于:

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

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

答案 3 :(得分:2)

这不是未定义的行为,也不是错误。来自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

修改

我会试着打破这个,所以希望你能更好地理解。

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

执行此代码时:

int a = 10;
a = a++;

您告诉编译器在增量之前为a赋值a。因此a在执行此操作后等于10。增量值11在“下面”中丢失。请注意,您没有将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;

这清楚了吗?

答案 4 :(得分:0)

为清楚起见,++ a和++之间存在不同。

它们中的两个产生相同的结果,即将 a 增加1,但是该过程略有不同,只能通过将其分配给另一个变量来看到它。

您可能正在寻找 pre post 增量之间的差异

案例1

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

案例2

 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。变量&#39; a&#39;创建数据类型为整数

     

<强> 2。变量&#39; a&#39;值分配为10

     

第3。检查右侧的可用性和数据类型的正确性。这意味着正在执行右侧的所有操作(增量&#39; a&#39;)。 &#39;一个&#39;现在是11

     

<强> 4。将增加后的值分配给&#39; a&#39;,即10,&#39; a&#39;现在是10

答案 5 :(得分:0)

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

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

答案 6 :(得分:-1)

你应该在案例2中打印出来。 post incement运算符结果始终是递增前的值。因此,首先将值10返回,然后将其递增为11,然后将运算符结果(10)赋值给左操作数。