具有后缀增量的三元运算符赋值

时间:2015-03-20 13:29:35

标签: c# increment ternary-operator

这有效,k增量:

k = 0;
k = ( false condition here ) ? 0 : k+=1;

这有效,k增量:

k = 0;
k = ( false condition here ) ? 0 : ++k;

这不起作用,k始终为0:

k = 0;
k = ( false condition here ) ? 0 : k++;

有人能解释一下发生了什么事吗?

编辑: 我不需要其他方法来写这个。 我不在乎是否可以用更简单的方式写出来。

在for循环中,无论是i ++还是++我都能工作。 为什么这里的行为不同?

4 个答案:

答案 0 :(得分:1)

如果你想知道幕后发生了什么,我们可以看看IL水平。在此之前,我认为值得看看xanatos建议的++运算符的使用。

无论如何,让我们来看看第二种情况下生成的IL。请看右边的评论:

int k = 0; 
k =  false ? 0 : ++k;

IL_0001:  ldc.i4.0    // Allocate space for int k
IL_0002:  stloc.0     // assign 0 to k
IL_0003:  ldloc.0     // load k on top of the evaluation stack     --> our stack is [k]
IL_0004:  ldc.i4.1    // load value 1 at location 1 for variable k --> [k 1]
IL_0005:  add         // Pops and add the top two values on the evaluation stack, and push the result onto the stack. our stack is --> [1]
IL_0006:  dup         // Copies the current topmost value on the evaluation stack, and then pushes the copy onto the evaluation stack. which in our case is 1 --> [1 1]
IL_0007:  stloc.0     // Pop the top value on the stack at location 0 (e.g. assign it to k) --> [1]
IL_0008:  stloc.0     // same again, the stack is empty now --> []
IL_0009:  ret 

正如你所看到的,最后两个stloc.0将堆栈中的两个1分配给k。事实上,如果你考虑一下,我们有两个任务。一个用于++ k,另一个用于分配三元运算的结果。正如你所说的那样产生1.让我们看一下产生0的最后一个案例:

int k = 0; 
k =  false ? 0 : k++;

IL_0001:  ldc.i4.0    // Allocate space for int k
IL_0002:  stloc.0     // assign 0 to k
IL_0003:  ldloc.0     // load k on top of the evaluation stack     --> our stack is [k]
IL_0004:  dup         // Copies the current topmost value on the evaluation stack, and then pushes the copy onto the evaluation stack. which in our case is 1 --> [k k] in this case k is still 0!
IL_0005:  ldc.i4.1    // load value 1 at location 1 for variable k --> [k k 1]
IL_0006:  add         // Pops and add the top two values on the evaluation stack, and push the result onto the stack. our stack is --> [k 1] // because k+1 is equal 1
IL_0007:  stloc.0     // Pop the top value on the stack at location 0 (e.g. assign it to k) --> [1]
IL_0008:  stloc.0     // Pop the top value on the stack at location 0 (e.g. assign it to k) but in this case k is still zero!!!!! --> []

正如您可以看到IL中的注释,两个stloc.0指令最终将k的原始值(即0)分配给k本身。这就是为什么在这种情况下你会得到0而不是1。

我没有给出你的问题的解决方案,而只是解释了如何在MSIL下面的级别处理这些“简单”操作。

希望它有所帮助。

答案 1 :(得分:0)

让我们更容易:

int x = 1;
x = x++;
// x still 1

为什么?

对于运算符优先级,首先执行++运算符,然后执行=赋值

让我们看一下++。来自https://msdn.microsoft.com/en-us/library/aa691363%28v=vs.71%29.aspx

If x is classified as a variable:

x is evaluated to produce the variable 

The value of x is saved. 
**1 is saved**

The selected operator is invoked with the saved value of x as its argument. 
**2 is produced**

The value returned by the operator is stored in the location given by the evaluation of x. 
**2 is put into x**

The saved value of x becomes the result of the operation.
**1 is returned**

现在我们有了作业:x = 1。因此,x被分配twice,一次使用2,一次使用1

答案 2 :(得分:0)

i++++i在for循环中的工作方式不同。

请考虑以下for循环定义:

for (int i=0; i<1; ++i)

可以写成:

for (int i=0; 1 >= i ; ++i)

这相当于写作:

for (int i=0; 1 >= ++i; /*No function here that increments i*/)

在这种情况下,在比较之前执行增量,并且永远不会执行循环的内容。

现在考虑这个循环:

for (int i=0; i<1; i++)

可以写成:

for (int i=0; 1 >= i ; i++)

这相当于写作:

for (int i=0; 1 >= i++; /*No function here that increments i*/)

在这种情况下,在比较之后执行增量,并且循环的内容将被执行一次。在循环结束时,我的值为1.

您可以通过执行以下操作来测试:

int i;
for (i=0; i<1; i++)
{
  Console.WriteLine("i in the loop has a value of: " + i);
}
Console.WriteLine("i after the loop has a value of: " + i);

同样的规则也适用于三元运营商。

这种情况将在将值赋值给k之前执行增量,并且k将是26:

int k=25;
k= (false) ? 0 : ++k

这种情况在将值赋给k后将执行增量,k将为25:

int k=25;
k = (false) ? 0 : k++;

k + = 1与++运算符不同,k- = 1与 - 运算符不同。 k + = 1实际上是2个简明易懂的操作:

k = k+1

首先取k的值,在内存中加1,然后将值赋回k。

所以在三元例中:

int k=25;
k = (false) ? 0 : k+=1;

k将为26.分配运算符从右到左进行评估。因此编译器将首先评估k + = 1 - 使得k 26.然后执行三元比较,然后将26分配给k。

要点:

++ / - 是特殊的运算符,在执行表达式的评估时,它会影响它。 ++ x或--x - ++或 - 将在任何比较之前进行评估。 x ++或x-- - ++或 - 将在任何比较后进行评估

答案 3 :(得分:0)

注意何时混合帖子增量和分配。当您将它们与赋值一起使用时,会出现前后增量之间的差异。

后增量(++)函数实现返回原始未触摸的输入值(它保存临时副本)并递增输入:

i = 0
i = i++

后增量++函数将作为输入i=0并将增加它。此时i实际上将是1,但后增量函数会返回原始值0,因此i将被重新分配,最终值将为{{} 1}}

在使用i ++或++的经典for循环0中,我不会有所作为,因为在递增时没有赋值。这个for循环可能导致您头痛而不是for(int i=0; i < val; i++ )