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() にはバッファの先頭へのポインタが渡されるため、これは理にかなっています。

ループ内でバッファを何度も定義する特定の理由はありますか? または、これに関する私の基本的な理解は正しいですか?

4

6 に答える 6

8

recv、asreadおよび他の同様の関数は、バッファーの以前の内容を気にせず、結果を書き込むためだけに使用します。

とにかく違いが生じるわけではありません。バッファを初期化していないため、変数をループに対してローカルとして宣言しても、その内容は「未定義」になります。

また、ほとんどの C 実装では:

  • その変数を初期化しないということは、その場所でスタック上にあるものは何でも取得することを意味します。これは、前の反復であったのと同じ場所を取得することを意味し、事実上、ループ外の変数。
  • スタック割り当ては安価です。一般に、レジスタを調整するだけで済みます。
  • 実際には、それらはさらに安価です。通常、レジスタの調整は関数の開始時に行われ、すべてのローカル変数が考慮されます。ローカル変数のスコープは、関数の開始時に割り当てられるため、コンパイル時の構造になります。

代わりに、明らかに、変数を初期化した場合は異なります。初期化を実行するコードは、反復ごとに実行する必要があります。しかし、上で述べたように、何も初期化する必要recvはなく、バッファの現在の状態を気にしないだけです。

于 2012-09-23T01:04:37.593 に答える
5

無駄ではありません。この変数のスコープを宣言します。コンパイラは、このスコープ外のスタックからより多くを割り当てずに、他の目的のためにスタック上のスペースを再利用する場合があります。実行時に余分な費用は必要ありません。コンパイラはコンパイル時に必要なスタック領域を計算し、スタック ポインタを関数の先頭で 1 回だけ調整します。

于 2012-09-23T01:02:09.340 に答える
2

ループ内で変数を宣言すると、スタック スペースが確保されます。内容をクリアしたり、変数に触れたりすることはありません。したがって、このスタイルの宣言は、ループの外側で宣言するよりも高価ではありません。

于 2012-09-23T01:02:04.923 に答える
2

ループ内で変数を定義するのは、構成にコストがかかる場合にのみ悪いことであり、C ではめったにありません。

最も基本的な最適化でも、ループの各反復でスタック ポインターを変更する必要はありません。多くのコンパイラは、デバッグ モードで配列をゼロ初期化しますが、このバッファが巨大でない限り、大きな問題にはなりません。

C++ では、ループ外で 1 回だけ変数を構築するだけで済むのであれば、高価なコンストラクターで変数を宣言しないことを考えるかもしれませんが、それはここでは問題になりません。

于 2012-09-23T01:04:48.513 に答える
1

また、宣言をループの外に移動すると、特に配列などのより大きな構造体の場合、コードが高速になると考えていました。これは、malloc(ヒープ)データの場合によくあることだと思います。mallocを呼び出してループ内で解放することで、オーバーヘッドに多くの時間を浪費する可能性があるためです。(あなたのような)スタックデータの場合、これは大きな問題ではないと思います。

しかし、最近、逆の状況に遭遇しました。宣言を内部ループの外に移動し、実際にはコードが遅くなってしまいました。私はこれについていくつかの可能な説明を思いついた:

  1. 宣言がより広い範囲に移動されたとき、コンパイラーはコードを効果的に最適化することができませんでした。
  2. ループの反復間で大量のデータがメモリに保持されていたため、キャッシュの使用効率が低下していました。

とにかく、これについての適切なリファレンスはありませんが、定義をループの内外に移動すると、状況に応じてコードが速くなったり遅くなったりする可能性があります。コードを変更する前後のパフォーマンスを測定して、違いがあるかどうかを確認する必要があります。

于 2012-09-23T02:53:25.667 に答える
1

私はいつも、ループ内で変数を定義するべきではないという印象を受けてきました。それは不必要または無駄だからです。

あなたは常に間違った印象を受けており、根拠がないだけでなく、非常に悪い慣行 (時期尚早の最適化) を非常に良い慣行と比較して、変数を可能な限り使用に近づけて宣言しています。

于 2012-09-23T02:02:39.097 に答える