C#中i=i++問題的分析與備忘

來源:互聯網
上載者:User

今天在群裡有人問到:

int i = 0; i = i++; Console.WriteLine( i );
以上代碼輸出的結果是多少?

我很自以為是的回答是:1

可結果為什麼不是1呢?先說一下我的分析思路

這段小程式產生的IL代碼為:

  .maxstack  3  .locals init (int32 V_0,           int32 V_1)  IL_0000:  ldc.i4.0  IL_0001:  stloc.0  IL_0002:  ldloc.0  IL_0003:  dup  IL_0004:  ldc.i4.1  IL_0005:  add  IL_0006:  stloc.0  IL_0007:  stloc.1  IL_0008:  ldloc.1  IL_0009:  call       void [mscorlib]System.Console::WriteLine(int32)  IL_000e:  ret

其中dup指令的解釋為:duplicate the top value of the stack (拷貝棧頂的值)

本來棧中的值為:0,執行過dup指令後棧中的值就變成:0|0了(|表示棧中各個值間的分隔,這裡表示棧中有兩個值)

可以看出就因為這個dup指令才導制了最後i的值還是變成了0

那麼是不是只要有++操作就會產生dup指令呢?於是我把代碼改成以下形式:

int i = 0; i++; Console.WriteLine( i );

得到的IL代碼為:

  .maxstack  2  .locals init (int32 V_0)  IL_0000:  ldc.i4.0  IL_0001:  stloc.0  IL_0002:  ldloc.0  IL_0003:  ldc.i4.1  IL_0004:  add  IL_0005:  stloc.0  IL_0006:  ldloc.0  IL_0007:  call       void [mscorlib]System.Console::WriteLine(int32)  IL_000c:  ret

可以看到並未出現dup指令,至此我們可以推斷當把++之類(i++/++i)的結果值賦予一個變數時才會出現dup指令,為此我再進行了如下驗證:

int i = 0; int j = i++; Console.WriteLine( j );

得到的IL代碼為:

.maxstack  3.locals init (int32 V_0,         int32 V_1)IL_0000:  ldc.i4.0IL_0001:  stloc.0IL_0002:  ldloc.0IL_0003:  dupIL_0004:  ldc.i4.1IL_0005:  addIL_0006:  stloc.0IL_0007:  stloc.1IL_0008:  ldloc.1IL_0009:  call       void [mscorlib]System.Console::WriteLine(int32)IL_000e:  ret

dup指令再次出現了,同理我還驗證了:

++i / i-- / --i

的情況

那麼為什麼會出現這樣的情況呢?

Java中有一段類似此問題解釋:

在這裡jvm裡面有兩個儲存區,一個是暫存區(是一個堆棧,以下稱為堆棧),另一個是變數區。
語句istore_1是將堆棧中的值彈出存入相應的變數區(賦值);語句iload_1是將變數區中的值暫存如堆棧中。
因為i = i++;是先將i的值(0)存入堆棧,然後對變數區中的i自加1,這時i的值的確是1,但是隨後的istore_1又將堆棧的值(0)彈出賦給變數區的i,所以最後i = 0。
又因為i = ++i;是先對變數區中的i自加1,然後再將變數區中i的值(1)存入堆棧,雖然最後執行了istore_1,但也只是將堆棧中的值(1)彈出賦給變數區的i,所以i = ++i;的結果是i = 1。

我想CLR的實現機制應該是與JVM中基本相同的,也理解了為什麼結果不是1的原因了,可還有個疑問,不管Java還是C#為什麼要這樣設計呢?這樣設計有什麼好處嗎?

然後我注意到了MSDN中的一句言簡意賅話:

第一種形式是首碼增量操作。該操作的結果是運算元加 1 之後的值。

第二種形式是尾碼增量操作。該運算的結果是運算元增加之前的值。

回頭再來看我們的代碼:

int j = i++;

j是什嗎?j就是i++的結果,MSDN中說明了i++的結果就是i在這條語句執行之前的值,很明顯j就是0了,那麼對於:

i = i++;

呢?這裡的意思很明顯就是i最後的結果就是i++的結果,i++的結果是0,所以i最後也就是0了,為了實現++運算子的定義(該運算的結果是運算元增加之前的值),所以在IL中使用dup指令對i之前的值(i++的結果)進行了拷貝(暫存),我想這樣理解問題就會簡單很多了

以上只代表個人觀點,歡迎拍磚:)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.