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

时间:2020-03-06 14:32:11  来源:igfitidea点击:

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

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)

解决方案

level ++会将级别传递给DoStuff,然后递增级别以在其余函数中使用。这可能是一个非常讨厌的错误,因为递归将永远不会结束(根据所示,DoStuff始终会传递相同的值)。也许++ level是相反的意思,因为这与level ++相反(递增级别,并将递增的值传递到DoStuff中)?

级别+1将级别+1传递到DoStuff中,而其余部分的级别保持不变。

首先是在水平中使用该值,然后将其递增。

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

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

" level ++"返回" level"的当前值,然后递增" level"。
" level + 1"根本不改变" level",但是以"(level + 1)"的值调用" DoStuff"。

因为第一个示例实际上等效于:

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

注意,我们也可以编写++ level。那将等同于:

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

我认为最好不要过度使用++和-operators;它很快就会引起混乱和/或者不确定实际发生的事情,并且现代的C ++编译器无论如何都不会使用这些运算符生成更有效的代码。

级别+1将任何级别+1发送给该函数。
level ++将级别发送给函数,然后将其递增。

我们可以进行++级的操作,这很可能会为我们提供所需的结果。

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

第二个示例使用'index'的值加1,但不更改'index'的内容。

因此,根据我们想要在这里做什么,商店中可能会有一些惊喜!

就我的经验而言,参数表达式首先被求值,并获得level的值。
变量本身在函数被调用之前就增加了,因为编译器不在乎我们是否使用表达式作为参数……否则,它所知道的是它应该增加值并获得旧值作为结果。表达。

但是在我看来,这样的代码确实很草率,因为试图变得聪明,它使我们必须三思而后行。

level ++的返回值将是level,因此将level传递给DoStuff。这可能是一个非常讨厌的错误,因为递归将永远不会结束(从所示的DoStuff总是以相同的值传递)。也许是" ++ level"或者" level + 1"的意思呢?

" level + 1"将" level + 1"传递到" DoStuff"中,而在其余功能中," level"保持不变。

后增量运算符(variable ++)与该函数完全等效

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)"。

为了阐明所有其他答复:

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

DoStuff(a++);

等效于:

DoStuff(a);
a = a + 1;

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

DoStuff(++a);

等效于:

a = a + 1;
DoStuff(a);

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

DoStuff(a + 1);

等效于:

b = a + 1;
DoStuff(b);

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

public DoStuff(int level)
{

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

它实际上增加了level的值。

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

实际上不会增加​​level的值。

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

虽然很诱人地将其重写为:

DoStuff(++level);

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

level++;
DoStuff(level);

当我们使用允许运算符重载的语言时,已经定义了'+ <integer>'来执行除前缀'++'之外的其他操作。

再说一次,我只在学校项目中看到过这样的可憎之处*,如果我们在野外遇到这种情况,我们可能有一个很好的,有据可查的理由。

[*一堆整数,如果我没记错的话。按下并弹出" ++"和"-",而" +"和"-"执行常规算术]

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