1

ループ外の変数

int number = 0;
for(int i = 0; i < 10000; i++){
     number = 3 * i;
     printf("%d",number);
}

またはループ内の変数

for(int i = 0; i < 10000; i++){
     int number = 3 * i;
     printf("%d",number);
}

どちらが推奨され、どちらがパフォーマンスに優れていますか?

編集:

これは私が言っていることを示すための単なる例です。私が知りたいのは、ループ内とループ外で変数を定義することが同じことを意味するのか、それとも違いがあるのか​​ということだけです。

4

5 に答える 5

6

早い段階で何かを学ぶ時間です。このようなものに対して行うことができる最適化は、printfの面では無関係になります。

Printfは非常に遅くなります。計算を5倍にして、測定可能な速度の低下を得ることができません。これは、端末への印刷の性質にすぎません。

編集した質問については、ループ内またはループ外で定義することに違いはありません。想像してみろ

for (i = 0; i < 500; i++) {
  int a = i * 3;
}

と同じです

int forloop::a; // This doesn't work, the idea is to show it just changes the scope
for (i = 0; i < 500; i++) {
  a = i * 3;
}

ループのローカルスコープで定義されているため、定義されているループの外でその変数を使用する必要がない限り、これらは同じコードを生成します。だから...もっとこのように:

int forloop::a;    // Still not valid code, just trying to show an explanation
namespace forloop {
for (i = 0; i < 500; i++) {
  a = i * 3;
}
} // namespace forloop

これが不明な場合は、詳細を説明するか、別の方法で説明することをお知らせください。

于 2012-04-03T22:37:48.397 に答える
2

最初はパフォーマンスに煩わされないでください。すべての前に安全にしてください。

私はあなたの懸念のために ScottMeyers(Effective C ++)を引用します: 「宣言を可能な限り延期する」。したがって、2番目のパターンの方が安全です。

例:

int j = 0;
for(int i = 0; i < 10000; i++){
    j = 3 * i;
    printf("%d",j);
}
...
// Use of j out of control!!!
int k = j * 5;

次に、2番目のパターンを使用します。

for(int i = 0; i < 10000; i++){
    int j = 3 * i;
    printf("%d",j);
}
...
// j not declared at this point.
// You get informed of the mistake at compile time, which is far much better.
int k = j * 5; 
于 2012-04-03T22:53:32.457 に答える
2

あなたはC++タグを持っていて、質問の中で「文字列の宣言」について言及しています。したがって、パフォーマンスに違いがある可能性があります(もちろん、printfがパフォーマンスに影響を与える可能性があります)。単純でない変数を宣言することは、コンストラクターを呼び出すことを意味します。これは、取るに足らない量の作業を意味する場合があります。その場合、ループ内でそれを宣言することは、無実の宣言のように見えるものに重要な作業を隠す可能性があります。

一般に、答えは、パフォーマンスを本当に気にし、サンプルコードを変数を宣言する2つの場所の違いの例としてのみ扱う場合は、単純でない変数の場合は、ループの外側で宣言する方がよいということです。 、セマンティクスが各反復で一時の新しいバージョンを必要としない限り。

パフォーマンスが問題であるかどうかを最初に確認する場所は他にもたくさんありますが、特にコンパイラよりも不変であると言う方がはるかに簡単な場合は、常にループ不変条件をループから移動することを検討してください。そして、宣言のように見えるものは、C++ではそのカテゴリに分類できます。

(ばかげた)例として、

int k = 43;
for ( int i = 0; i < N; ++i )
    {
    int j = 17 + k; // k was previously defined outside the loop, but doesn't change in it
    l = j * j; // l was also declared outside the loop
    }

優れた最適化コンパイラは、kが定数であり、jには常に60が割り当てられ、lには3600 N回割り当てられ、ループを削除してlへの単一の割り当てに置き換えることができることを認識できます。ここで、kとjは両方ともループ不変条件です。

しかし、それほど優れていないコンパイラーは、そのチェーン内の1つのリンクさえも見逃し、ループを作成してしまう可能性があります。

あなたが持っているときにコンパイラが物事を理解するのは難しくなります

 Foo k( 43 );  // a class that takes an int argument to its constructor
 for( int i = 0; i < N; ++i )
    {
    Bar j( k ); // a Bar takes an int argument, adds 17 and stores it.
    l = j.squared();
    }

同じ不変量。バーの仕組みの内部を見ずに検出するのは簡単ではありません。コンストラクターと2乗メソッドがインラインでない場合は、速度を遅くしました。

于 2012-04-03T23:05:24.023 に答える
0

あなたの質問に答えるために、そしてつまらないことではありません:

2つのバリアントの違いは、異なる「変数環境」で変数を宣言していることですnumber。つまり、スコープが変更されます。中括弧によって可変環境が与えられます{ ... }。このように新しい中括弧を開くたび{ ... { ... } ... }に、古い環境の中で新しい変数環境を宣言します。つまり、次のように宣言すると、次numbersのようになります。

{ ... { int numbers; ... } ... }

この変数は、最も内側の環境でのみ表示または存在します。それで

{ ... { int numbers; ... } ... do_something(numbers); ... }

コンパイラエラーが発生します。

そして、パフォーマンスに関する懸念事項:どちらのバリアントもパフォーマンスが優れているわけではありません。すべてではないにしても、ほとんどのコンパイラは同じアセンブリを提供します。

于 2012-04-03T22:50:18.173 に答える
0

この場合、printf( "%d"、i * 3)は、変数を定義するよりも優れています。

于 2012-04-03T22:34:02.000 に答える