7

ポインタの間接参照の速度について質問があります。私はそのような構造を持っています:

typedef struct _TD_RECT TD_RECT;
struct _TD_RECT {
  double left;
  double top;
  double right;
  double bottom;
};

私の質問は、これらのどれがより速くなるのか、そしてなぜですか?


ケース1:

TD_RECT *pRect;
...
for(i = 0; i < m; i++)
{
   if(p[i].x < pRect->left) ...
   if(p[i].x > pRect->right) ...
   if(p[i].y < pRect->top) ...
   if(p[i].y > pRect->bottom) ...
}

ケース2:

TD_RECT *pRect;
double left = pRect->left;
double top = pRect->top;
double right = pRect->right;
double bottom = pRect->bottom;
...
for(i = 0; i < m; i++)
{
   if(p[i].x < left) ...
   if(p[i].x > right) ...
   if(p[i].y < top) ...
   if(p[i].y > bottom) ...
}

したがって、ケース1の場合、ループはpRectポインターを直接逆参照して、比較値を取得します。ケース2では、関数のローカルスペース(スタック上)で新しい値が作成され、値がpRectからローカル変数にコピーされました。ループを通して、多くの比較があります。

私の考えでは、ローカル変数はスタック上のメモリ参照でもあるため、同じように遅くなりますが、よくわかりません...

また、インデックスでp []を参照し続けるか、pを1つの要素でインクリメントして、インデックスなしで直接逆参照する方がよいでしょうか。

何か案は?ありがとう :)

4

5 に答える 5

12

おそらく、最新のコンパイラでは違いがないことに気付くでしょう。それらのほとんどは、ループ内で変更されない式の一般的な部分式の削除をおそらく実行します。C ステートメントとアセンブリ コードの間に単純な 1 対 1 のマッピングがあると想定するのは賢明ではありません。私のアセンブラーのスキルを恥じさせる gcc ポンプアウト コードを見たことがあります。

しかし、これは C や C++ に関する質問ではありません。なぜなら、ISO 標準はその方法を義務付けていないからです。確実に確認する最善の方法は、次のような方法でアセンブラー コードを生成しgcc -S、2 つのケースを詳細に調べることです。

また、この種のマイクロ最適化から離れて、アルゴリズムの選択などのマクロ レベルにもっと集中すれば、投資に対してより多くのリターンを得ることができます。

そして、すべての最適化の質問と同様に、推測ではなく測定してください。影響を与える可能性のある変数が多すぎるため、ターゲット環境で現実的なデータを使用してさまざまなアプローチをベンチマークする必要があります。

于 2010-10-21T11:25:27.407 に答える
3

パフォーマンスに重大な違いが生じる可能性はほとんどありません。各オプションを複数回実行してプロファイルし、確認できます。テストでコンパイラの最適化が設定されていることを確認してください。

double の格納に関しては、const を使用するとパフォーマンスが低下する可能性があります。アレイの大きさは?

ポインター演算の使用に関しては、これはより高速になる可能性があります。

rect で left < right を知っていれば、即座に最適化できます (確かにそうである必要があります)。x < left の場合、> right にすることもできないため、「else」を入れることができます。

大きな最適化がある場合、配列内のすべての項目をループする必要がなく、それらすべてに対して 4 つのチェックを実行する必要がないことから得られます。

たとえば、配列を x と y でインデックス付けまたはソートした場合、バイナリ検索を使用して、x < left を持つすべての値を見つけて、それらだけをループすることができます。

于 2010-10-21T11:29:23.583 に答える
1

ループの反復ごとに pRect へのポインターを逆参照していないため、2 番目のケースの方が高速である可能性が高いと思います。

実際には、最適化を行っているコンパイラはこれに気づき、生成されるコードに違いはないかもしれませんが、pRect が p[] 内のアイテムのエイリアスである可能性があるため、これを防ぐことができます。

于 2010-10-21T11:23:20.623 に答える
0

完全に最適化されていないコンパイル (-O0) でさえ、提示された 2 つのケースに対して異なるコードを生成する場合、私は驚かれることでしょう。最新のプロセッサで操作を実行するには、データをレジスタにロードする必要があります。そのため、自動変数を宣言した場合でも、これらの変数はメイン メモリには存在せず、プロセッサの浮動小数点レジスタの 1 つに存在します。これは、変数を自分で宣言しない場合でも当てはまります。したがって、C++ コードで一時変数を宣言した場合でも、生成されるマシン コードに違いはないと思います。

しかし、他の人が言ったように、コードをアセンブラーにコンパイルして、自分の目で確かめてください。

于 2010-10-21T13:43:26.727 に答える
0

最適化コンパイラは、構造体アクセスがループ不変であることを認識し、ループ不変のコード モーションを実行して、2 つのケースが同じに見えるようにします。

于 2010-10-21T11:29:01.277 に答える