若是不使用結果值, i++
和++i
之間會有性能差別嗎? 程序員
請不要讓「哪一個更快」的問題成爲使用哪一個的決定因素。 您永遠都不會在意那麼多,此外,程序員的閱讀時間比機器學習的時間要昂貴得多。 機器學習
使用對人類閱讀代碼最有意義的方法。 函數
我老是喜歡預增量,可是... 性能
我想指出的是,即便在調用operator ++函數的狀況下,若是函數被內聯,編譯器也將可以優化掉臨時函數。 因爲operator ++一般很短,而且常常在標頭中實現,所以極可能會內聯。 學習
所以,出於實際目的,這兩種形式的性能可能沒有太大區別。 可是,我老是更喜歡預增量,由於直接表達我想說的彷佛更好,而不是依靠優化器來解決。 優化
一樣,減小優化器的工做量可能意味着編譯器運行得更快。 spa
我能夠想到後綴比前綴增量慢的狀況: code
想象一下,將具備寄存器A
的處理器用做累加器,而且它是許多指令中使用的惟一寄存器(某些小型微控制器實際上就是這樣)。 對象
如今,假設如下程序及其轉換爲假設的程序集: 內存
前綴增量:
a = ++b + c; ; increment b LD A, [&b] INC A ST A, [&b] ; add with c ADD A, [&c] ; store in a ST A, [&a]
後綴增量:
a = b++ + c; ; load b LD A, [&b] ; add with c ADD A, [&c] ; store in a ST A, [&a] ; increment b LD A, [&b] INC A ST A, [&b]
請注意b
的值是如何被強制從新加載的。 使用前綴遞增,編譯器能夠只遞增該值並繼續使用它,可能避免從新加載它,由於所需的值在遞增以後已經存在於寄存器中。 可是,使用後綴增量,編譯器必須處理兩個值,一個是舊值,另外一個是增量值,正如我在上面顯示的那樣,這將致使更多的內存訪問。
固然,若是不使用增量值,例如單個i++;
語句,不管後綴或前綴使用狀況如何,編譯器均可以(而且確實)簡單地生成增量指令。
附帶說明一下,我想提到一個存在b++
的表達式不能簡單地用++b
轉換爲一個表達式而無需任何額外的努力(例如,經過添加- 1
)。 所以,若是將二者做爲某個表達式的一部分,則將它們進行比較是不正確的。 一般,在表達式中使用b++
狀況下,不能使用++b
,所以即便++b
可能更有效,也徹底是錯誤的。 若是表達式請求它,固然是例外(例如a = b++ + 1;
能夠更改成a = ++b;
)。
首先:在C中, i++
和++i
之間的區別能夠忽略不計。
到細節。
++i
更快 在C ++中,若是i
是某種帶有重載增量運算符的對象,則++i
效率更高。
爲何?
在++i
,對象首先增長,而後能夠做爲const引用傳遞給任何其餘函數。 若是表達式是foo(i++)
這是不可能的,由於如今須要在調用foo()
以前完成增量,可是須要將舊值傳遞給foo()
。 所以,在對原始文件執行增量運算符以前,編譯器被迫複製i
。 額外的構造函數/析構函數調用是最糟糕的部分。
如上所述,這不適用於基本類型。
i++
可能會更快 若是不須要調用構造函數/析構函數,這在C ++i
老是如此, ++i
和i++
應該同樣快,對嗎? 不。它們的速度幾乎同樣快,但可能會有一些細微的差別,大多數其餘應答者都採用了錯誤的方法。
如何能i++
更快?
關鍵是數據依賴性。 若是須要從內存中加載該值,則須要對其進行兩個後續操做,使其遞增並使用它。 對於++i
,須要先進行遞增, 而後才能使用該值。 使用i++
,使用不取決於增量,CPU能夠與增量操做並行執行使用操做。 區別最可能是一個CPU週期,所以它確實能夠忽略不計,可是確實存在。 這是許多人指望的另外一種方式。
內容提要:否。
i++
可能比++i
慢,由於可能須要保存i
的舊值以供之後使用,但實際上全部現代編譯器都會對其進行優化。
咱們能夠經過使用++i
和i++
查看此函數的代碼來證實這一點。
$ cat i++.c extern void g(int i); void f() { int i; for (i = 0; i < 100; i++) g(i); }
這些文件是相同的,除了++i
和i++
:
$ diff i++.c ++i.c 6c6 < for (i = 0; i < 100; i++) --- > for (i = 0; i < 100; ++i)
咱們將對其進行編譯,並得到生成的彙編器:
$ gcc -c i++.c ++i.c $ gcc -S i++.c ++i.c
咱們能夠看到生成的對象文件和彙編文件都是相同的。
$ md5 i++.s ++i.s MD5 (i++.s) = 90f620dda862cd0205cd5db1f2c8c06e MD5 (++i.s) = 90f620dda862cd0205cd5db1f2c8c06e $ md5 *.o MD5 (++i.o) = dd3ef1408d3a9e4287facccec53f7d22 MD5 (i++.o) = dd3ef1408d3a9e4287facccec53f7d22