以下两个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)
答案 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++
的返回值为level
,therefore
将level
传递给DoStuff
。这可能是一个相当讨厌的错误,因为递归永远不会结束(从显示的DoStuff
总是以相同的值传递)。可能代之以++level
或level + 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
的当前值,然后递增level
。
level+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的值。 在调用函数之前,变量本身会递增,因为编译器并不关心您是将表达式用作参数还是其他...所有它知道它应该增加值并获取旧值作为结果表达
但是在我看来,像这样的代码真的很草率,因为通过尝试变得聪明,它会让你不得不三思而后行。