在循環語句中,for(i=0;i<n;i++)和for(i=0;i<n;++i)有什麼區別?

我同學有簡單地告訴我,i++的話要先copy出一個i然後賦值,用原來的i繼續其他運算,最後再把copy出來的i做個increment,然後返還給原來的i。

而++i直接在原來的i上做increment。

結論:當n很大的時候,++i速度比i++快。

比如語法上a = i++; 是等號右邊的變數賦值給左邊的變數,但是賦值應發生在所有運算之後。這就比較矛盾,如果用上訴理論就能解釋得清楚。

請問他說的對嗎?


如果 i 是系統類型,兩者沒有性能區別。絕大多數編譯器可以生成同效率代碼。由於所謂的多餘複製的變數並沒有被用到(i++的返回值無人使用),所以編譯器優化之後跟++i等價。

兩者性能區別理論上存在於當 i 是一個自定義的類,並且這個類重載了++操作符,並且這個類重載「後增量」操作符時使用了值複製作為返回值的情況,在這種情況下,有時編譯器能優化掉多餘的複製,有時不能。所以++對於自定義對象類型來說會有題主所說的情況。


不開優化,並沒有什麼不同

開啟優化,編譯器是不會在這種地方拖慢你的程序的

能把循環內的乘法優化成兩個add指令,循環本身的跳轉也大大簡化

優化之後的代碼已經看不到所謂的i++和++i了

(哪位聚聚能給解釋一下那兩個add指令是如何變成乘法的)

有些人就是不肯平心靜氣地和人說話,是吧


一:i++ 和 ++i

從Java的角度來說,這兩個沒有區別。(證據,生成的位元組碼一樣。)

從C/C++的角度來說,++i可能更好一些,因為不用存儲一個中間變數。(但我懷疑這個是可以被編譯器優化掉的。)

二:運算順序

討論一個語句中如,i = i++ + i++。究竟++操作是何時發生的,對於C/C++語言可能沒有意義,因為是未定義行為,對於Java來說是有意義,因為Java明確定義了運算順序。


在C++里,假如i是int,那麼沒有任何不同,無論開不開優化,你沒有使用自增後的i值,編譯器根本就不會「複製」一個i。

如果i是個自定義類型,又自定義了前綴和後綴++操作符,那自然是不一樣的。


習慣用++i,但我相信編譯器對此的優化,不會在意它的性能。

對於a = i++;那段,我不大清楚你的問題,不知道下面這樣說能不能幫你理解。

你說的「等號右邊的變數賦值給左邊的變數」,那既然是「值」,這個值也就可以來自於另外一個變數(假設是t),t保存了i自增前的值,然後把t返回給了左邊進行賦值操作。

把++理解成下面這個方法。

int jiajia(int i)
{
int t = i;
i += 1;
return t;
}

a = i++;就變成了a = jiajia(i);


我想說的是現在已經是2015年了,編譯器都發展了幾十年了連這點優化都做不到也好意思拿得出來?程序優化的重點應該放在項目的性能瓶頸上,而不是摳這種幾乎無意義的細枝末節。

再說了,如果你非覺得編譯器不可信非要寫成++i,那我可以告訴你把

for(int i=0; i&

寫成

for(int i=n-1; i&>=0; --i)

會更快(彙編可以少一個CMP指令,當然主流的編譯器基本都會自動幫你做這樣的優化)

你會把程序中所有循環改成下面那種嗎?


所有支持++的語言中,按定義++i的速度一定大於等於i++


在循環語句中,for(i=0;i&

沒。

我同學有簡單地告訴我,i++的話要先copy出一個i然後賦值,用原來的i繼續其他運算,最後再把copy出來的i做個increment,然後返還給原來的i。

而++i直接在原來的i上做increment。

無依據的臆測。

比如語法上a = i++; 是等號右邊的變數賦值給左邊的變數,但是賦值應發生在所有運算之後。

錯。

====================================

做點正事,不要問沒有意義的問題。

現代程序設計不怎麼追求速度,通常認為代碼可讀性優先於程序效率。

即使要求效率也是從演算法和數據結構入手,

從for語句中挖掘速度無異於從牙縫裡找吃的希望吃的更飽些。


按C來說

i++把i增加1,返回i增加前的值

至於是先計算整個表達式還是先增加i應該是未定義的

++i先把i加1,返回i的引用

在for里i++和++i由於返回值沒有被使用,因此會被優化成一樣的結果


本來,這樣的問題我不會回答,心裡說「編譯器君掩面不語」後跳到下一個問題。

但是沖著你的第一句話:「(這個問題估計1萬個程序員也不到1個能真正領悟)」。我忍不住進來跟你說,同學,你一定要成為一個萬里挑一的程序員啊。


for循環中不好說明,不妨假設有這樣一個表達式:

int i = 3;

int k;

k = ++i; //#1

k = i++; //#2

前置遞增運算符:對象遞增加一再使用

即:

/* #1等價於 */

i = i+1; //i的值為4

k = i; //k 的值為4

後置遞增運算符:創建一個臨時對象,將臨時對象替換調用原變數的位置,原變數+1

即:

/* #2等價於 */

k = int(i); //int(i) 是一個臨時對象,值為4

i = i+1; //i 的值為5

也就是說後置遞增相比前置遞增會創建一個臨時對象int(i),使用臨時對象賦值給k,所以後置遞增會比前置遞增慢那麼一丟丟。


學校里就講到++i先將i加一再運算,i++把原值運算後再加一,好low,突然感覺。。。。。。


只是人的習慣問題,就好比為什麼每個語言第一個程序叫hello world而不是hello monkey


加一段timer不就知道了么,我只記得老師說不管是++i還是i++都比i=i+1快,i++在n十分大的時候慢於++i,原理早忘了(或許應該查看下彙編)


測試一下


i++返回的是i本身的值,++i返回的是i+1的值,可以寫一個小程序測試一下就知道了。


這個問題把我們送回了80年代那個勒緊褲腰帶開發程序的日子,多兩三條代碼程序會慢到死嗎,我相信現在已經不是主要問題了,就算出現問題,那也是編譯器作者的問題,不是程序員的問題。


推薦閱讀:

編寫彙編代碼最好的IDE是什麼?
做了很久的項目,結果代碼全沒了是一種怎樣的體驗?
在 GitHub 可以做什麼,用戶又習慣做些什麼?
如何看待「初學者把自己新寫或寫的爛的項目放到 GitHub 就是浪費公共資源,給中國人丟臉」的言論?
Microsoft Visual Studio可以用來開發ios和android么?

TAG:程序員 | 代碼 | C編程語言 | C | CC |