27

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

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

,

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

在阅读了下面的一些回复后,我认为发布 level++、++level 和 level+1 的堆栈跟踪是值得的,以突出这个问题的欺骗性。

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

// 级别++

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

// ++级

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

// 等级+1

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

15 回答 15

44

To clarify all the other responses:

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

DoStuff(a++);

Is equivalent to:

DoStuff(a);
a = a + 1;

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

DoStuff(++a);

Is equivalent to:

a = a + 1;
DoStuff(a);

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

DoStuff(a + 1);

Is equivalent to:

b = a + 1;
DoStuff(b);

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

于 2008-09-22T12:08:36.543 回答
29

Because the first example is really equivalent to:

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

Note that you can also write ++level; that would be equivalent to:

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

It's best not to overuse the ++ and -- operators in my opinion; it quickly gets confusing and/or undefined what's really happening, and modern C++ compilers don't generate more efficient code with these operators anyway.

于 2008-09-22T12:00:51.197 回答
27

level++ will pass level into DoStuff and then increment level for use in the rest of the function. This could be a fairly nasty bug as the recursion will never end (from what is shown DoStuff is always being passed the same value). Perhaps ++level is meant instead, as this is the opposite of level++ (increments level and passes the incremented value into DoStuff)?

level+1 will pass level+1 into DoStuff and leave level unchanged for the rest of the function.

于 2008-09-22T11:58:07.927 回答
12

the return value of level++ will be level and therefore pass level into DoStuff. This could be a fairly nasty bug as the recursion will never end (from what is shown DoStuff is always being passed with the same value). Perhaps ++level or level + 1 is meant instead?

level + 1 will pass level + 1 into DoStuff and leave level unchanged for the rest of the function.


The post-increment operator (variable++) is precisely equivalent to the function

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

while the pre-increment operator (++variable) is precisely equivalent to the function

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

Therefore, if you expand the operator inline into the code, the operators are equivalent to:

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);

It is important to note that post-increment is not equivalent to:

DoStuff(a);
a = a + 1;

Additionally, as a point of style, one shouldn't increment a value unless the intention is to use the incremented value (a specific version of the rule, "don't assign a value to a variable unless you plan on using that value"). If the value i + 1 is never used again, then the preferred usage should be DoStuff(i + 1) and not DoStuff(++i).

于 2008-09-22T12:08:08.010 回答
2

The first is using the value in level and THEN incrmenting it.

The latter is using level+1 as a passed variable.

于 2008-09-22T11:58:39.593 回答
1

level++ returns the current value of level, then increments level. level+1 doesn't change level at all, but DoStuff is called with the value of (level + 1).

于 2008-09-22T11:59:56.847 回答
1
public DoStuff(int level)
{

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

It actually increments the value of level.

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

doesn't actually increment the value of level.

Not a huge problem before the function call, but after the function call, the values will be different.

于 2008-09-22T12:11:16.863 回答
1

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

于 2008-09-22T13:05:45.953 回答
0

The first code snippet uses the post-operation increment operator, so the call is made as DoStuff(level);. If you want to use an increment operator here, use DoStuff(++level);.

于 2008-09-22T11:58:51.620 回答
0

level+1 sends whatever level+1 is to the function. level++ sends level to the function and then increments it.

You could do ++level and that would likely give you the results you want.

于 2008-09-22T12:02:38.523 回答
0

The first example uses the value of 'index', increments the value and updates 'index'.

The second example uses the value of 'index' plus 1 but does not change the content of 'index'.

So, depending on what you are wanting to do here, there could be some surprises in store!

于 2008-09-22T12:02:49.177 回答
0

Whilst it is tempting to rewrite as:

DoStuff(++level);

I personally think this is less readable than incrementing the variable prior to the method call. As noted by a couple of the answers above, the following would be clearer:

level++;
DoStuff(level);
于 2008-09-22T12:13:31.460 回答
0

当您使用允许运算符重载的语言时,'+ <integer>' 已被定义为执行后置和前缀 '++' 之外的其他操作。

再说一次,我只在学校项目中看到过这种可憎的事*,如果你在野外遇到这种情况,你可能有一个非常好的、有据可查的理由。

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

于 2008-09-22T12:49:42.670 回答
0

用最简单的方式来说,++var它是一个前缀运算符,它将在计算表达式的其余部分之前递增变量。,一个后缀运算符,在计算表达式的其余部分var++递增一个变量。当然,正如其他人所提到的,它只创建一个临时变量(在内存中单独),它以 constant 启动并递增。var+1var1

于 2012-09-14T21:46:26.660 回答
-2

As far as my experience goes, the parameter expression is evaluated first, and gets a value of level. The variable itself is incremented before the function is called, because the compiler doesnt care whether you are using the expression as a parameter or otherwise... All it knows is that it should increment the value and get the old value as the result of the expression.

However in my opinion, code like this is really sloppy, since by trying to be clever, it makes you have to think twice about what is really happening.

于 2008-09-22T12:05:08.673 回答