什么时候++不会产生与+1相同的结果?

时间:2008-09-22 11:55:41

标签: c# stack increment

以下两个C#代码片段会产生不同的结果(假设在递归调用之前和之后都使用了变量级别)。为什么呢?

public DoStuff(int level)
{
  // ...
  DoStuff(level++);
  // ...
}

public DoStuff(int level)
{
  // ...
  DoStuff(level+1);
  // ...
}

在阅读下面的一些回复之后,我认为值得发布级别++,++级别和级别+ 1的堆栈跟踪,以突出显示欺骗这个问题的方式。

我为这篇文章简化了它们。递归调用序列以DoStuff(1)开始。

// level ++

DoStuff(int level = 1)
DoStuff(int level = 2)
DoStuff(int level = 2)
DoStuff(int level = 2)

// ++ level

DoStuff(int level = 4)
DoStuff(int level = 4)
DoStuff(int level = 3)
DoStuff(int level = 2)

// level + 1

DoStuff(int level = 4)
DoStuff(int level = 3)
DoStuff(int level = 2)
DoStuff(int level = 1)

15 个答案:

答案 0 :(得分:44)

澄清所有其他回复:

+++++++++++++++++++++

DoStuff(a++);

相当于:

DoStuff(a);
a = a + 1;

+++++++++++++++++++++

DoStuff(++a);

相当于:

a = a + 1;
DoStuff(a);

+++++++++++++++++++++

DoStuff(a + 1);

相当于:

b = a + 1;
DoStuff(b);

+++++++++++++++++++++

答案 1 :(得分:29)

因为第一个例子实际上相当于:

public DoStuff(int level)
{  
  // ...
  int temp = level;
  level = level + 1;
  DoStuff(temp);
  // ...
}

注意你也可以写++ level;这相当于:

public DoStuff(int level)
{  
  // ...
  level = level + 1;
  DoStuff(level);
  // ...
}

在我看来,最好不要过度使用++和 - 运算符;它很快就会让人感到困惑和/或未定义真正发生的事情,而现代C ++编译器无论如何都不能用这些运算符生成更高效的代码。

答案 2 :(得分:27)

级别++ 会将级别传递到 DoStuff ,然后递增级别以用于该功能的其余部分。这可能是一个相当讨厌的错误,因为递归永远不会结束(从显示的 DoStuff 始终传递相同的值)。也许 ++ level 是指,因为这与 level ++ 相反(递增级别并将递增的值传递给 DoStuff )?

级别+ 1 会将级别+ 1 传递到 DoStuff ,并保持级别不变,其他部分功能

答案 3 :(得分:12)

level++的返回值为levelthereforelevel传递给DoStuff。这可能是一个相当讨厌的错误,因为递归永远不会结束(从显示的DoStuff总是以相同的值传递)。可能代之以++levellevel + 1

level + 1会将level + 1传递给DoStuff,并保留level以保留其余功能。


后增量运算符(变量++)与函数

完全等效
int post_increment(ref int value)
{
    int temp = value;
    value = value + 1
    return temp;
}

而预增量运算符(++变量)恰好等同于函数

int pre_increment(ref int value)
{
    value = value + 1;
    return value;
}

因此,如果将运算符内联扩展到代码中,则运算符等效于:

DoStuff(a + 1)

int temp = a + 1;
DoStuff(temp);

DoStuff(++a)

a = a + 1;
DoStuff(a);

DoStuff(a++);

int temp = a;
a = a + 1;
DoStuff(temp);

重要的是要注意,后增量等同于:

DoStuff(a);
a = a + 1;

此外,作为样式点,除非打算使用递增的值(规则的特定版本,“除非您打算使用,否则不要为变量赋值),否则不应增加值那个价值“)。如果永远不再使用值i + 1,则首选用量应为DoStuff(i + 1)而不是DoStuff(++i)

答案 4 :(得分:2)

第一种是使用级别中的值,然后使用它来填充它。

后者使用level + 1作为传递变量。

答案 5 :(得分:1)

level++返回level的当前值,然后递增levellevel+1根本不会更改level,但DoStuff的值为(level + 1)

答案 6 :(得分:1)

public DoStuff(int level)
{

  // DoStuff(level);
  DoStuff(level++);
  // level = level + 1;
  // here, level's value is 1 greater than when it came in
}

它实际上会增加级别的值。

public DoStuff(int level)
{
  // int iTmp = level + 1;
  // DoStuff(iTmp);
  DoStuff(level+1);
  // here, level's value hasn't changed
}

实际上并没有增加级别的值。

在函数调用之前不是一个大问题,但在函数调用之后,值将是不同的。

答案 7 :(得分:1)

在++级中,您使用的是后缀运算符。该运算符在使用变量后工作。也就是说,在它被放入被调用函数的堆栈之后,它会递增。另一方面,level + 1是简单的数学表达式,它被计算并将结果传递给被调用的函数。 如果要先增加变量然后将其传递给被调用函数,可以使用前缀运算符:++ level

答案 8 :(得分:0)

第一个代码片段使用后操作增量运算符,因此调用为DoStuff(level);.如果要在此处使用增量运算符,请使用DoStuff(++ level);。

答案 9 :(得分:0)

level + 1发送任何级别+ 1是该函数。 level ++向该函数发送级别,然后递增它。

你可以做++级别,这可能会给你你想要的结果。

答案 10 :(得分:0)

第一个示例使用'index'的值,增加值,更新'index'。

第二个例子使用'index'的值加1但不改变'index'的内容。

所以,根据你想在这里做什么,可能会有一些惊喜!

答案 11 :(得分:0)

虽然很有可能重写为:

DoStuff(++level);

我个人认为这比在方法调用之前递增变量更不易读。正如上面几个答案所指出的,以下内容会更清楚:

level++;
DoStuff(level);

答案 12 :(得分:0)

当您使用允许运算符重载的语言时,以及'+< integer>'已被定义为除了后缀和前缀'++'之外的其他内容。

然后,我再次在学校项目中看到了这样的可憎之处*,如果你在野外遇到这种可能,你可能会有一个非常好的,有充分记录的理由。

[*一堆整数,如果我没弄错的话。 '++'和' - '推出并弹出,而'​​+'和' - '执行正常的算术]

答案 13 :(得分:0)

以最简单的方式来说,++var是一个前缀运算符,并且会在之前递增变量,然后计算表达式的其余部分。 var++,一个后缀运算符,在后计算表达式的其余部分后递增变量。正如其他人已经提到的那样,var+1只创建一个临时变量(在内存中分离),该变量由var启动并以常量1递增。

答案 14 :(得分:-2)

根据我的经验,首先评估参数表达式,并获取level的值。 在调用函数之前,变量本身会递增,因为编译器并不关心您是将表达式用作参数还是其他...所有它知道它应该增加值并获取旧值作为结果表达

但是在我看来,像这样的代码真的很草率,因为通过尝试变得聪明,它会让你不得不三思而后行。