2012-09-23 57 views
6

我一直覺得我不應該在循環中定義一個變量,因爲它是不必要的或浪費的。這使我想知道如果下面的recv()函數需要一個新的緩衝區循環的每次迭代:爲什麼在循環內部定義這個緩衝區?

while (totalBytesRecvd < echoStrLen) 
{ 
    char buffer[BUFSIZE]; 
    numBytes = recv(sock, buffer, BUFSIZE - 1, 0); 
    ... 
    totalBytesRecvd += numBytes; 
    buffer[numBytes] = '\0'; 
    fputs(buffer, stdout); 
} 

爲的recv()的文檔沒有提及它如何使用緩衝區指針什麼。爲了更好的理解,我試着在循環之前定義緩衝區,並且recv()似乎覆蓋了緩衝區,而不是重新定義緩衝區。這是有道理的,因爲recv()傳遞了一個指向緩衝區開始的指針。

是否有一個特定的原因來定義一個緩衝區一遍又一遍的循環內?或者,我對此的基本理解是正確的?

回答

8

recv,作爲read和其他類似的功能,不關心緩衝區的以前的內容,它只是用它來寫結果。

不是說它會有所作爲:因爲您沒有初始化緩衝區,即使您將該變量聲明爲循環的本地變量,其內容也將是「未定義的」。

此外,在大多數C實現:

  • 沒有初始化,這將採取一切正好是堆在那個位置,這反過來又意味着將採取相同的位置上可變機構,它在前面的迭代中,有效地給你與循環外的變量完全相同的結果。
  • 堆棧分配很便宜 - 通常他們只需要調整一個寄存器;
  • 實際上,它們甚至更便宜:通常寄存器調整僅在函數開始時完成,佔所有局部變量;局部變量的範圍變成只是一個編譯時構造,因爲它在函數啓動時被分配。

顯然,相反,如果你初始化您的變量將是不同的 - 執行初始化代碼將不得不在每次迭代運行;但是,如上所述,不需要初始化任何東西,recv只是不關心緩衝區的當前狀態。

+0

+1,比我的回答好得多。 – Martin

+0

迄今爲止所有非常有用(和類似)的答案。任何人都可以指出我的來源?或者我可以在我的編譯器文檔中找到所有這些嗎?編譯器優化在我讀過的C編程書中被掩蓋了。 – Nocturno

+2

我的源代碼花費太多時間看編譯器生成的彙編程序:)。一般來說,不要擔心這種優化。爲正確的工作使用正確的算法,並且只有考慮到這些類型的調整,才能演示一段代碼*需要*優化。 – Martin

2

在循環中聲明一個變量只是爲它保留了堆棧空間;它不會清除內容或以其他方式觸摸變量。因此,這種聲明的風格並不比在循環之外聲明更昂貴。

5

這不是浪費。它聲明瞭這個變量的範圍。編譯器可能爲了其他目的回收堆棧上的空間,而不是從堆棧中分配更多的空間。它在運行時不需要額外的開銷 - 編譯器在編譯時計算必要的堆棧空間,並在函數的開頭只調整一次堆棧指針。

2

定義在一個循環的變量只有當它的價格昂貴,構建壞,這是很少C.​​

隨着連最基本的優化,它甚至沒有去打擾修改堆棧指針的情況下,循環的每次迭代。許多編譯器會在調試模式下初始化一個數組,但除非這個緩衝區很大,否則這不太可能是一個大問題。在C++中,你可能會考慮不用一個昂貴的構造函數來聲明一個變量,如果你只能在循環之外構造它,但這不會成爲一個問題。

1

我一直覺得我不應該在循環中定義一個 變量,因爲它不必要或浪費。

你一直是一個不正確的印象,以及一個不僅是毫無根據的,但抽得一個非常不好的做法 - 過早的優化 - 對一個非常好的一個,聲明變量接近它們作爲可能。

1

我也曾經認爲將聲明移出循環會導致代碼更快,特別是對於像數組這樣的大型結構。我認爲malloc'd(堆)數據通常是這樣,因爲通過在循環中調用malloc和free可以浪費很多開銷。對於堆棧數據(比如你的)我不認爲這是一個大問題。

但是,我最近遇到了相反的情況,在那裏我把一個聲明從一個內部循環中移出來,並且實際上以代替了較慢的代碼。我想出了這幾個可能的解釋:

  1. 在報關的時候被轉移到更廣的範圍,編譯器無法作爲有效的優化代碼。
  2. 在循環迭代之間內存中存儲了大量數據,導致緩存使用效率低下。

無論如何,我沒有一個很好的參考,但將定義移入或移出循環可以使代碼更快或更慢,具體取決於情況。您必須在更改代碼前後測量性能,以查看是否有差異。

+0

'我也曾經認爲將聲明移出循環會導致代碼更快,特別是對於像數組這樣的大型結構。 - *爲什麼*你認爲? '我認爲malloc'd(堆)數據通常是這樣的 - 分配不是聲明!如果你有像'int foo = very_long_calculation(rand())'這樣的語句,那麼在循環中移動*計算*當然是很昂貴的。對malloc的調用有什麼不同? –