本文講述了 c/c++ 中 自增(自減)運算子 的一些知識~自增(自減)運算子應該是 c/c++ 程式設計中的基礎知識了,而自增(自減)運算子又有兩種形式,分別是前置自增(自減)和後置自增(自減)(出於簡單考慮,後文僅以自增運算子進行舉例講解).
譬如表示式 ++i 和 i++ 就分別表示對 i 進行前置自增 和 對 i 進行後置自增,用**來說明的話, ++i(前置自增) 大概和以下**等價:
i = i + 1;
return i;
而 i++(後置自增) 則大概和以下**等價:
v = i;
i = i + 1;
return v;
可以看到, ++i 和 i++ 雖然都對 i 進行了增 1 操作,但是 ++i 返回了自身,而 i++ 返回了乙個臨時變數(用以儲存 i 之前的數值),所以 i++ 比 ++i 要消耗更多的 cpu 資源(因為要使用臨時變數),所以自己編碼時也慢慢形成了乙個習慣:多用前置自增,少用後置自增.
雖然就現在的程式開發來講,似乎我們已經不必特別關心 前置自增 和 後置自增 的效率差異了,在合適的情況下,編譯器對於 前置自增 和 後置自增 也能生成同樣高效的彙編**了,但是自己依然堅持著上面的編碼習慣(多用前置自增,少用後置自增),理由也很簡單:雖然 前置自增 和 後置自增 的效率相仿甚至相同,但是 前置自增 仍然在理論上要優於 後置自增.
(下面的示意圖是 for 迴圈中 前置自增 和 後置自增 編譯器(msvc)對應生成的彙編**,可以看到,兩者對應生成的彙編**是一致的)
但後面從 game engine architecture 中卻了解到了乙個有些顛覆的知識:前置自增效率上其實一般是要慢於後置自增的 !!!
這裡的原因是 前置自增 會比 後置自增 產生更多的 指令流水線停頓(stall),一般情況下,雖然 前置自增 對比 後置自增 會產生更少的指令操作,但是其產生的指令流水線停頓對效率的影響更大,所以我們應該:多用後置自增,少用前置自增!
自己初看到這個結論時自然是將信將疑,畢竟和自己之前的認知大相徑庭,雖然我也認可書中給出的理由解釋,但還是決定要親自測試驗證一下:
// pre-increment profile
int index = 0;
int value = 0;
for (int i = 0; i < count; ++i)
// post-increment profile
int index = 0;
int value = 0;
for (int i = 0; i < count; ++i)
首先確定 前置自增 和 後置自增 確實生成了不同的彙編**:
後面就是簡單的測量執行時間了,結果也確實如書中所說:
後置自增平均要比前置自增 快 20% 左右~
總結多用後置自增,少用前置自增,雖然 後置自增 會產生更多的指令操作,但是一般情況下對指令流水線的影響更小,所以相比 前置自增 其實反而更加高效.
從一開始懵懂的編寫後置自增**,到後來了解了內部原理後改用前置自增,再到現在了解了更多原理之後改回後置自增,頗有些"返璞歸真"的味道~
更新我在 c# 中也同樣測試了一下 前置自增 和 後置自增 的效率差別,發現結論與之前是相反的:
前置自增平均要比後置自增 快 23% 左右~
看來在非 native 語言中還是應該優先選擇 前置自增.
進一步總結
關於 前置自增 和 後置自增 的效率問題不能一概而論,不同語言可能產生迥異的效率差別, profile 可以幫助我們確定較優的自增方式~
自增自減運算子
自增自減運算子 i 先使用i,然後i i 1 i 先使用i,然後i i 1 i 先i i 1然後使用i i 先i i 1 然後使用i 以下使用vc下除錯的結果,不同的編譯器可能有不同的結果。i 3 例1printf d i 結果輸出4 例2printf d i 結果輸出3 例3printf resu...
自增 ,自減 運算子
自增1運算子記為 其功能是使變數的值自增1。自減1運算子記為 其功能是使變數值自減1。自增1,自減1運算子均為單目運算,都具有右結合性。可有以下幾種形式 i i自增1後再參與其它運算。i i自減1後再參與其它運算。i i參與運算後,i的值再自增1。i i參與運算後,i的值再自減1。在理解和使用上容易...
自增和自減運算子
自增和自減運算子 在c語言中有許多運算子,邏輯運算,賦值運算,關係運算 其中最難理解的莫過於自增 和自減 運算了。自增 自減 有兩種方式,下面分別進行分析。1 在前。i i 其用法是在整個表示式運算之前先進行自增 自減 運算,然後再進行表示式運算。例如進行如下計算 intx y x 8 y x 執行...