關於變數在for迴圈內外定義的思考
在c#或java裡面,我們通常會這樣寫for迴圈:
for(int i = 0;i<10;i++) { Console.WriteLine(i); }
前一陣子,我突發奇想,如果按照下面這樣寫,會不會比上面的執行效率高一些:
1 2 3 4 5 |
int i
= 0;
for (;
i<10 ;i++)
{
Console.WriteLine(i);
}
|
因為我覺得最上面的那種方式,每次迴圈都會宣告一個變數,說不定會影響效率,於是百度了一下,發現其他人也有這個疑惑,特意百度了一些資料,在此做個綜合。
首先是在內層迴圈中定義變數到底會不會存在重複分配的問題,這涉及到編譯器的優化,不過主流編譯器(如vs和gcc)這一塊優化都比較好,不會反覆分配變數。函式的定義是編譯器的事情,執行的時候不存在什麼定義,更沒有什麼開銷。
除非是類物件或者結構體物件, 在for迴圈裡面與外面, 開銷可能會不一樣.基本資料型別, 那是一樣的, 編譯器肯定會優化這個東西。
一般來說, 在進入函式時, 所有的棧變數都分配好空間了. 所以那個for變數寫在哪裡都是一樣的. 具體你可以看一下反彙編程式碼, 全部就展現在你眼前了,我檢視過C#的IL程式碼,發現兩種寫法的IL程式碼是一樣的,說明沒有區別。
棧中的空間在編譯這個程式碼的時候大小就確定下來了,執行這個方法時空間就已經分配好了,不要想當然的以為宣告一次就要分配一次空間,那是c語言,java可以重用這些超出作用域的空間。只要用javap檢視方法位元組碼,看看使用的區域性變量表的大小和使用方式即知java這種基於虛擬機器的語言,是跟單純的C不同,C語言的原則是相信程式設計師能做好一切,因此它不會幫你做多少事情,需要考慮程式碼優化,記憶體佔用等。
不過,自己在程式設計的時候要注意不要讓上一次的結果影響到下一次迴圈,比如上一次 a = 3, 當下一次迴圈在給a賦值的時候出了錯誤,而你捕獲了錯誤,卻沒修正a的值,程式繼續執行,那麼這時候a=3還成立,可能就會有問題了,如果是每次都重新定義,那就不存在這樣的問題。
最後總結:
- 對於使用int等基本資料型別作為迴圈變數,只要你用的優化方面足夠給力的主流的編譯器,完全不需要關心在迴圈外還是迴圈內定義迴圈變數。
- 如果迴圈變數本身是複雜的物件,建議在迴圈外定義好,並且在
for
迴圈的賦值語句、判斷語句中,都要避免重複建立物件。