a = a++ 永遠等於原值

探討 C#  編譯器對於  a++ 的處理方式

前一陣子在論壇上有人問了個很有趣的問題:『為什麼 int a=0; a = a++; 後,a 還是 0?』。

首先,我們來瞧瞧以下程式碼是如何被執行的:

        static void Main(string[] args)
        {
            int a = 0;
            a++;
        }
  1. 記憶體裡會產生一個變數 a
  2. Push 一個 0 值給 Stack,此時 Stack 只有一個元素
  3. 將 Stack 頂層的值 Pop 出來,塞給 a 變數,此時 Stack 已經沒有任何元素
  4. (以上就是 int a = 0)
  5. 接著將 a 變數的值 Push 進 Stack,所以 Stack 有一個元素,值為 0 (也就是 a 變數的值)。
  6. 接著 Push 一個 1 值給 Stack,此時 Stack 有兩個元素
  7. 然後把 Stack 頂層的值,也就是 1,Pop 出來,此時 Stack 剩一個元素
  8. 再將 Stack 頂層的值,也就是 0,Pop 出來,此時 Stack 已經沒有任何元素
  9. 將 1 和 0 相加的結果 Push 回 Stack,所以 Stack 有一個元素,值為 1 (也就是相加的結果)
  10. 然後把 Stack 頂層的值,也就是 1,Pop 出來,塞給 a 變數
  11. 結束

以上的程序其實和以下的程式碼是一樣的:

        static void Main(string[] args)
        {
            int a = 0;
            a = a + 1;
        }

 

接著來看看主題吧,下一段程式碼是怎麼執行的:

        static void Main(string[] args)
        {
            int a = 0;
            a = a++;
        }
  1. 記憶體裡會產生一個變數 a
  2. Push 一個 0 值給 Stack,此時 Stack 只有一個元素
  3. 將 Stack 頂層的值 Pop 出來,塞給 a 變數,此時 Stack 已經沒有任何元素
  4. (以上就是 int a = 0)
  5. 接著將 a 變數的值 Push 進 Stack,所以 Stack 有一個元素,值為 0 (也就是 a 變數的值)。
  6. 有趣的地方在這裡,因為 a = a++ 會造成兩次回傳,一個是自己,一個是等號左邊的變數,所以此時會將 Stack 頂層的值 Pop 出來,然後複製這個值。
  7. 接著將剛剛的兩個值 Pop 進 Stack,所以此時 Stack 有兩個元素,內容值都是 0
  8. 接著 Push 一個 1 值給 Stack,此時 Stack 有三個元素,值分別為 1,0,0
  9. 然後把 Stack 頂層的值,也就是 1,Pop 出來,此時 Stack 剩兩個元素
  10. 再將 Stack 頂層的值,也就是 0,Pop 出來,此時 Stack 剩一個元素
  11. 將 1 和 0 相加的結果 Push 回 Stack,所以 Stack 有兩個元素,值為 1 (也就是相加的結果) 和 0
  12. 將 Stack 頂層的值 Pop 出來指派給 ++ 運算子前面的變數,因為程式碼是 a++,所以指派給 a,這個值是 1,STack 只剩一個元素 0
  13. 將 Stack 頂層的值 Pop 出來指派給 = 左邊的變數,因為程式碼是 a = ,所以很巧的也是指派給 a ,這個值是 0,Stack 清空
  14. 所以無論你怎麼看,除非你看得到 Stack 的流程,否則你永遠看到的 a 值都是 0

 

以上還是 C# 編譯器沒有使用最佳化編譯的狀態,如果是最佳化編譯,以上面那兩行程式碼,就只會做兩件事:

  1. Push 一個 0 值進入 Stack
  2. 把它 Pop 掉
  3. 沒了

 

這篇簡單地使用 Stack 的運算過程解釋一下為何 a = a++ 無論怎麼搞都是原來的值的原因,我覺得還滿有趣的。