2

bufferは、配列を含む複数のメンバーで構成される構造体であると仮定します。

通常の最適化フラグを使用してコンパイルすると、これら 2 つのコード スニペットを実行すると、どのようなパフォーマンスの違いが期待できるでしょうか?

buffer buf;
for (int i = 0; i < BIG_ENOUGH_NUMBER; i++) {
   init(huge_file, i, &buf);
}

// buf is not used afterward

...

void init(FILE* f, int i, buffer* b) {
   ... // b is filled using f, according to i
   do_something(b);
}

for (int i = 0; i < BIG_ENOUGH_NUMBER; i++) {
   init(huge_file, i);
}

...

void init(FILE* f, int i) {
   buffer buf;
   ... // buf is filled from scratch using f, according to i
   do_something(&buf);
}
4

2 に答える 2

3

最初の答えは、それらをベンチマークすることです。

2 番目の答えは、アセンブリ言語にコンパイルして、ソースを確認することです。最適化フラグの有無にかかわらずこれを行うと、有益な場合があります。

be abelenky が指摘したように、どちらの場合もbufスタックにあります。私の一般的な推測では、buf を引数として渡す必要がないため、2 番目のケースは (私が使用したコンパイラーを使用して) 少し高速になると思います。スタックに割り当てる必要がありますが、スタックの割り当ては通常、関数の呼び出しフレームのわずかに異なるサイズです。そのフレームの大きさに関係なく、同じ量の作業 (スタック ポインターの調整) を行う必要があります。

したがって、生成されたコードの主な違いは、2 番目のケースでは "PUSH" 命令が 1 つ少ないことです。(それらがすべてレジスターにある場合、それは少し異なります。)

これは、最適化の影響を受ける可能性があります。たとえばbuf、それぞれの場合に最終的にレジスターになるかどうかです。しかし、buf を設定するための欠落しているコードがこれに影響を与える可能性があるため、推測はしません。

上記は、コンパイラの動作を調べた結果に基づく私の推測であることに注意してください。理論的には、コンパイラは、結果のプログラムが正しく実行される限り、好きなようにコードを変換できます。

于 2012-04-26T00:01:38.157 に答える
0

@TJD は彼のコメントで正しいです。

どちらの場合もbufスタック上にあり、サイズが大きい場合は問題を引き起こす可能性があります。通常、を使用してヒープから大きなアイテムを割り当てる必要がありますmalloc

つまり、2番目の例でbufは完全にinit関数内にあり、関数が呼び出し元に戻った瞬間に消えます(この例では呼び出し元は名前がありません)。

init行われたすべての作業が失われ、呼び出し元の関数に表示されないため、事実上役に立ちません。

最初の例では、リターンbuf後も有効です。init

于 2012-04-25T23:05:06.570 に答える