ポインタを用いると動作が速くなる(処理が軽くなる)
配列に添え字を書くよりも、ポインタを用いた方が動作が速い(処理が軽い)
ポインタの悪いところばかり書いていると使いたくなくなりそうなので、良いところにも触れておきましょう。
(ポインタやC言語を嫌々(いやいや)使ってるのではなく、メリットが大きいからデメリットを承知で使っているのです)
#define indexof(a) (sizeof(a)/sizeof(a[0])) int Direct_func() { int found = 0; int i; for(i = 0; i < indexof(TestList); i++) { if(TestList[i].first) found = 1; } return found; }
int Good_Func() { ST_LIST *list; int found = 0; int i; list = &TestList[0]; for(i = 0; i < indexof(TestList); i++, list++) { if(list->first) found = 1; } return found; }
メリットが無いのでは、ポインタを扱うリスクを背負う必要はありません。
理由は処理速度です。
処理速度を求めない場合は、直接参照を用いましょう。
直接参照(TestList[i].first)で書いた場合、これをコンパイルすると、次のようなアセンブラに変換されます。
- TestListのアドレスをメモリから読み取る。
- iの値をメモリから読み取る。
- アドレスを計算し、レジスタに格納する。
アドレス = TestListのアドレス + TestList[0]のサイズ × i + firstの位置
- アドレスの示す場所に書かれている値を読み取って、返す
演算やメモリ/レジスタ操作が7ステップくらいと、作業数は大したことはありませんが、乗算(×)が曲者(くせもの)です。
掛け算というものは処理時間が掛かるものです。
興味のある方は、足し算とビット演算だけで掛け算を実行する関数を作ってみると良いでしょう。
相応の処理量になることに驚かされると思います。
この例からも分かるように、足し算やメモリ/変数を扱う処理の方が数が多いことが分かります。
従って、掛け算などを高速処理する複雑な回路でCPUを作るよりも、単純で多用される処理をより高速で実行する回路でCPUを作ったほうがパフォーマンスが良いのです。
これをRISCと呼び、逆に複雑な処理も高速に実行する、複雑で回路の大きなCPUをCISCと呼ぶ様になりました。
(ARM等がRISC、68000やx86等がCISCと呼ばれていましたが、近年は様々な改善が重ねられて一概に分けられない様です)
とはいえ、掛け算も多用される処理の一つですので、実際には、高速なコア回路に掛け算回路が沿えられています。
そして必要に応じて掛け算回路に掛け算を実行させ、その間に単純な処理をコア回路で進める、といった形で実行されます。
しかし、掛け算回路の数は限られているので、掛け算が多いと、
掛け算が終わるのをコア回路が待つ、という時間が増えてしまい、トータルの時間が間延びしてしまうのです。
その為、掛け算を減らすことが、処理速度向上の手段となるわけです。
間接参照の場合、list++ と list->first なので、足し算だけで済みますので、処理量が少なく、動作が速く(軽く)なります。
“ポインタを用いると動作が速くなる(処理が軽くなる)” に対して1件のコメントがあります。
この投稿はコメントできません。
indexof(a) の定義ですが、除算が逆ではないでしょうか。
ご指摘ありがとうございます。
修正しました。
#define indexof(a) (sizeof(a[0])/sizeof(a))
↓
#define indexof(a) (sizeof(a)/sizeof(a[0]))
反省して、遅ればせながら動作確認しました。
ソース全文はソース倉庫に置いておきました。
このコードを手元の環境で実行したところ、約20倍くらいのスピード改善結果となりました。