- ポインターとダブルポインターを使用してメモリ位置にアクセスする場合、パフォーマンスに違いはありますか?
- もしそうなら、どちらが速いですか?
4 に答える
答えは実機に依存する可能性があるため、簡単な答えはありません。私の記憶が正しければ、一部のレガシー マシン ( PDP11など) では、単一の命令で「ダブル ポインター」アクセスが提供されていました。
しかし、これは今日の状況ではありません。メモリへのアクセスは見た目ほど単純ではなく、仮想メモリが原因で多くの作業が必要になります。この理由から - 私の推測では、最近のほとんどのマシンでは実際には二重参照が遅くなるはずです. 仮想アドレスから物理アドレスに2つのアドレスを変換して取得するには、より多くの作業を行う必要があります.
ただし、コンパイラはすでに「冗長な」アクセスを最適化している可能性があることに注意してください。
ただし、私の知る限りでは、「シングル アクセス」よりも「ダブル アクセス」の方が高速なマシンは存在しないため、シングル アクセスはダブル アクセスよりも悪くないと言えます。
補足として、私は実際のプログラムを信じており、その違いは(プログラムで行われる他の何かと比較して)無視できるものであり、非常にパフォーマンスに敏感なループで行われない限り、より読みやすいものは何でもしてください. また、可能であれば、コンパイラーがすでに最適化している可能性があります。
あなたが何かについて話していると仮定すると
int a = 10;
int *aptr = &a;
int **aptrptr = &aptr;
それからの費用は
*aptr = 20;
逆参照の 1 つです。が指すアドレスをaptr
最初に取得する必要があり、次にアドレスを格納できます。
のコスト
**aptrptr = 30;
2 つの逆参照です。が指すアドレスをaptrptr
最初に取得する必要があります。次に、そのアドレスに格納されているアドレスを取得する必要があります。次に、このアドレスを保存できます。
これはあなたが求めていたものですか?
したがって、必要に応じて単一のポインターを使用する方が高速です。
たとえば、ループ内でポインターまたはダブルポインターにアクセスする場合は、
while(some condition)
*aptr = something;
また
while(some condition)
**aptrptr = something;
コンパイラは、逆参照がループの開始時に 1 回だけ行われるように最適化する可能性が高いため、コストは N ではなく 1 つの余分なアドレス フェッチだけです。ここで、N はループの実行回数です。
EDIT:(1)Amitが正しく指摘しているように、ポインターアクセスの「方法」は明示的にCのものではありません...基礎となるアーキテクチャに依存します。マシンが単一の命令として二重逆参照をサポートしている場合、大きな違いはないかもしれません。彼は、例としてPDP11のインデックス据え置きアドレッシング モードを使用しています。そのような命令がさらに多くのサイクルを食いつぶすことに気付くかもしれません... ハードウェアのドキュメントを参照し、C コンパイラが特定のアーキテクチャに適用できる最適化を調べてください。
PDP11アーキテクチャは 1970 年代頃のものです。私の知る限り (誰かが知っているなら、この投稿をお願いします!)、ほとんどの RISC アーキテクチャにはそのような二重逆参照がなく、私の知る限り、おそらく 2 つのフェッチを行う必要があります。
したがって、単一のポインターを使用する方が一般的にはおそらく高速ですが、特定のアーキテクチャーが他のアーキテクチャーよりもこれを適切に処理する可能性があり、前述のようにコンパイラーの最適化により、違いがごくわずかになる可能性があることに注意してください...プロファイルする必要があることを確認するあなたのコードとあなたのアーキテクチャについて読んでください:)
私は興味を持って、次のシナリオを設定しました。
int v = 0;
int *pv = &v;
int **ppv = &pv;
ポインターの逆参照を試み、逆アセンブリを調べたところ、次のことがわかりました。
int x;
x = *pv;
00B33C5B mov eax,dword ptr [pv]
00B33C5E mov ecx,dword ptr [eax]
00B33C60 mov dword ptr [x],ecx
x = **ppv;
00B33C63 mov eax,dword ptr [ppv]
00B33C66 mov ecx,dword ptr [eax]
00B33C68 mov edx,dword ptr [ecx]
00B33C6A mov dword ptr [x],edx
そこに逆参照用の追加の mov 命令があることがわかるので、私の最善の推測は、二重の逆参照は必然的に遅くなるということです。