[英]When does ++ not produce the same results as +1?
以下兩個C#代碼段產生不同的結果(假定在遞歸調用之前和之后都使用變量級別)。 為什么?
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)
為了闡明所有其他答復:
+++++++++++++++++++++
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)
{
// ...
int temp = level;
level = level + 1;
DoStuff(temp);
// ...
}
注意,您也可以編寫++ level。 那等於:
public DoStuff(int level)
{
// ...
level = level + 1;
DoStuff(level);
// ...
}
我認為最好不要過度使用++和-運算符; 它很快就會引起混亂和/或不確定實際發生的事情,並且現代C ++編譯器無論如何都不會使用這些運算符生成更有效的代碼。
level ++會將級別傳遞給DoStuff ,然后遞增級別以在其余函數中使用。 這可能是一個相當討厭的錯誤,因為遞歸將永遠不會結束(根據所示, DoStuff始終會傳遞相同的值)。 也許++ level是相反的意思,因為這與level ++相反(遞增level並將遞增的值傳遞給DoStuff )?
級別+1將級別+1傳遞到DoStuff中 ,而其余部分的級別保持不變。
level++
的返回值將是level
, therefore
將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)
。
首先是使用級別中的值,然后將其遞增。
后者使用level + 1作為傳遞變量。
level++
返回的當前值level
,然后遞增level
。 level+1
根本不會改變level
,但是DoStuff
的值是(level + 1)
。
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的值。
在函數調用之前這不是一個大問題,但是在函數調用之后,值將有所不同。
在level ++中,您正在使用后綴運算符。 使用該變量后,該運算符將起作用。 也就是說,將其放入調用函數的堆棧后,它會遞增。 另一方面,+ 1是簡單的數學表達式,它被求值並將結果傳遞給被調用的函數。 如果要先遞增變量,然后將其傳遞給被調用的函數,則可以使用前綴運算符:++ level
第一個代碼段使用后操作增量運算符,因此調用以DoStuff(level);進行。 如果要在此處使用增量運算符,請使用DoStuff(++ level);。
級別+1將任何級別+1發送給該函數。 level ++將級別發送給函數,然后將其遞增。
您可以進行++級別的操作,這很可能會為您提供所需的結果。
第一個示例使用“索引”的值,增加值並更新 “索引”。
第二個示例使用“索引”的值加1,但不更改“索引”的內容。
因此,根據您想要在這里做什么,商店中可能會有一些驚喜!
雖然很誘人地將其重寫為:
DoStuff(++level);
我個人認為,這比在方法調用之前增加變量的可讀性差。 如上面的幾個答案所述,以下內容將更加清楚:
level++;
DoStuff(level);
當您使用允許運算符重載的語言時,已經定義了'+ <integer>'來執行除后綴和前綴++之外的其他操作。
再說一次,我只在學校項目中看到過這樣的可憎之處*,如果您在野外遇到這種情況,您可能有一個很好的,有據可查的理由。
[*一堆整數,如果我沒記錯的話。 按下並彈出“ ++”和“-”,而“ +”和“-”執行常規算術]
簡而言之, ++var
是一個前綴運算符,它將在表達式的其余部分求值之前遞增變量。 后綴運算符var++
在對表達式的其余部分求值之后對變量進行遞增。 當然,正如其他人提到的那樣, var+1
只會創建一個臨時變量(在內存中是單獨的),該變量以var
並以常數1
遞增。
就我的經驗而言,參數表達式首先被求值,並獲得level的值。 變量本身在函數被調用之前就增加了,因為編譯器並不在乎您是否使用表達式作為參數……否則,它所知道的是它應該增加值並獲得舊值作為結果。表達。
但是在我看來,這樣的代碼確實很草率,因為通過嘗試變得聰明,它使您必須三思而后行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.