2011-12-20 105 views
59

我對C#編譯器如何處理前後增量和遞減有點困惑。C#前期和後期增量混淆

當我的代碼如下:

int x = 4; 
x = x++ + ++x; 

x將具有值10之後。我認爲這是因爲預增量設置爲x5,這使得5+5的計算結果爲10。然後後增量將更新x6,但不會使用此值,因爲那麼10將被分配到x

但是,當我代碼:

int x = 4; 
x = x-- - --x; 

然後x2之後。任何人都可以解釋爲什麼這是事實嗎?

+2

好問題!我們已經學會了從不寫代碼,你必須考慮它可以做什麼,但它會做什麼。 – RvdK 2011-12-20 09:32:30

+15

任何寫這樣的代碼的人都應該被取出並拍攝。 'x = x ++ + ++ x;'...沒有任何藉口。 – 2011-12-20 09:33:13

+15

這只是一個「學術」問題 - 我永遠也不會寫這樣的代碼:-) – Schweder 2011-12-20 09:41:24

回答

46

x--將是4,但會3日在--x的時刻,所以它會結束爲2,那麼你就必須

x = 4 - 2 

順便說一句,你的第一個案例將是x = 4 + 6

這裏是一個小例子,將打印出值爲每個部分,也許這樣你會更明白:

static void Main(string[] args) 
{ 
    int x = 4; 
    Console.WriteLine("x++: {0}", x++); //after this statement x = 5 
    Console.WriteLine("++x: {0}", ++x); 

    int y = 4; 
    Console.WriteLine("y--: {0}", y--); //after this statement y = 3 
    Console.WriteLine("--y: {0}", --y); 

    Console.ReadKey(); 
} 

此打印Ø UT

x++: 4 
++x: 6 
y--: 4 
--y: 2 
+3

感謝您的回答 - 我以爲在完成代碼行評估之後/之前執行後增量和預增量 - 但是它們在表達式中每個項目的評估之前/之前執行。 – Schweder 2011-12-20 09:38:13

+0

@Schweder,稍作修改:操作員在對其應用的變量進行評估之前/之前執行。不是表達式中的每個術語。 – Amy 2011-12-20 09:48:35

+2

@Inuyasha:糾正你的修正:操作符*總是*執行*在變量評估後作爲變量。前後運算符之間的差異僅爲*返回的值*,而不是*執行操作的順序*。 – 2011-12-20 16:49:49

-1

我認爲對於++ + ++情況的解釋是錯誤的:X

命令...........值

.... ..............未定義

INT X = 4 .......... 4

X ++ ........... .... 5(第一個被加數是4)

++ X ............... 6(第二被加數是6)

X = summand1 + summand2 ..4 + 6 = 10

類似的用於解釋 - - - 情況下是

命令........... X

的值..................未定義

INT X = 4 .......... 4

X --............... 3(subtactor是4)

--x ............... 2(減數爲2)

x =減法 - 減數。4-2 = 10

+0

我完全不明白你的回答,對不起。 – 2011-12-20 13:41:54

+0

@phresnel我糾正了答案中的一些錯誤。他的基本意思與你接受的答案一樣:我們實際上得到了10,因爲我們加了4和6; 2是4和2之間的差異。 – phoog 2011-12-20 19:42:41

16

讓我們看看那個會從該語句生成

IL_0002: ldloc.0  

荷載x的壓入堆棧的值IL。堆棧=>(4)

IL_0003: dup   

複製堆棧中最頂端的項目。堆棧=>(4,4)

IL_0004: ldc.i4.1  

將1推入堆棧。堆棧=>(1,4,4)

IL_0005: sub   

減去兩個最高值並將結果推送到堆棧。堆棧=>(3,4)

IL_0006: stloc.0  

將堆棧的最高值存回x。堆棧=>(4)

IL_0007: ldloc.0  

將x的值加載回棧中。堆棧=>(3,4)

IL_0008: ldc.i4.1  

將值1加載到堆棧上。堆棧=>(1,3,4)

IL_0009: sub   

減去兩者。堆棧=>(2,4)

IL_000A: dup   

重複頂部值=>(2,2,4)

IL_000B: stloc.0  

商店頂部值返回至x。堆棧=>(2,4)

IL_000C: sub  

減去兩個最高值。堆棧=>(2)

IL_000D: stloc.0 

將此值存回x。 X == 2

2

在這個例子中,

int x = 4; 
x = x++ + ++x; 

你可以打破它想:

x = 4++; which is = 5 
x = 4 + ++5; which is 4 + 6 
x = 10 

同樣,

int x = 4; 
x = x-- - --x; 

這裏,

x = 4--; which is = 3 
x = 4 - --3; which is 4 - 2 
x = 2 

簡而言之,可以說,替換x的當前值,但對於每個++或 - 從x中添加/減去一個值。

6

最有趣的事情是,您將得到與C++ .Net編譯器完全不同的答案。

int x = 4; 
x = x++ + ++x; // x = 11 
x = 4; 
x = x-- - --x; // x = -1 

當然的結果之間的差異是由不同的語義確定 - 它似乎正常。但是,儘管理解了兩個.net編譯器不以類似的方式表現這種基本的東西,我也感到困惑。

+2

在C++(不是Microsoft的非C++版本的C++之一)中,在完整表達式結束之前多次修改變量會產生未定義的行爲。 – 2011-12-20 13:40:56

+4

這與* parse *沒有任何關係。它與兩種語言關於順序點的不同允許語義有關。 – 2011-12-20 16:51:36

8

從您的評論:

我認爲,後和預增量後執行/完整的代碼行的評估之前 - 但他們執行後/每個項目的表達式中的評估之前。

你的誤解是非常普遍的。請注意,在某些語言(如C)中,不會在副作用變爲可見時指定它,因此它是合法的,但並非必需的,因爲您的語句在C中爲true。

這不是C#中的情況;在C#代碼表達式的左側副作用始終觀察代碼之前發生在右側執行(從單個線程;在多線程方案所有的賭注都關閉。)

對於更詳細的什麼樣的增量運營商在C#做的說明,請參閱:

What is the difference between i++ and ++i?

有到我寫這個經常被誤解的話題的文章非常多的其他鏈接存在。