i++ 與 ++i 如果在不影響結果的情況下使用,有可能是在 for 迴圈的遞增條件下,或是只是很單純的呼叫,可能因為編譯器最佳化的關係,兩者其實沒有什麼不同。
像是下面這樣單獨呼叫 ++i。
1 | var i = 0; |
或是像是下面這樣單獨呼叫 i++。
1 | var i = 0; |
其對應的 IL 都是一樣的:
1 | IL_0000: nop |
但在影響結果的情況下使用(像是處理完做了賦值的動作),除了結果不同外,還會多耗用一個堆疊位置,這邊以一個簡單的例子來看:
1 | var i = 0; |
對應的 IL 如下:
1 | IL_0000: nop |
整個運作是會先將堆疊內放置一個 0,然後將堆疊內的 0 取出放到區域變數 i,再將 i 的值放到堆疊內,這時堆疊內的值還是 0。
然後將堆疊內的 0 複製一份放至堆疊,這時堆疊內的值為 00。
接著將 1 放入堆疊,堆疊內的值變為 001。
再來從堆疊內取出兩個值相加後放回堆疊,堆疊內的值變為 01。
最後將堆疊內的值取出依序塞給區域變數 i 與 a。
可以看到這樣的處理最多需要的堆疊大小為 3。
再來來看 ++i,一樣用個間單的例子來看:
1 | var i = 0; |
其對應的 IL 如下:
1 | IL_0000: nop |
整個運作是會先將堆疊內放置一個 0,然後將堆疊內的 0 取出放到區域變數 i,再將 i 的值
放到堆疊內,這時堆疊內的值還是 0。
接著會在堆疊放置一個 1,這時堆疊內的值為 01。
再來從堆疊內取出兩個值相加後放回堆疊,堆疊內的值變為 1。
然後複製堆疊頂端的值,此時堆疊內的值為 11。
最後將堆疊內的值取出依序塞給區域變數 i 與 a。
這樣的處理最多需要的堆疊大小為 2。
所以在這種情境下,能避開 i++ 就避開,像是下面這樣的程式:
1 | var idx = 0 |
就可以將它改寫成下面這樣:
1 | var idx = -1; |
或是將它改成不影響結果的那種寫法也可以,