3

こんにちは、私は現在中間 C クラスにいますが、この考えが頭に浮かびました。

int multi[3][4]; // const multidimensional array

int* ptr = *multi; // ptr is a pointer variable that hold the address of multi const array

では、多次元配列の位置にアクセスするために、より速く/より小さく/最適化されたものは何ですか?

これ:

multi[3][1]; // index the value position

また

*(*(multi+2)+1); // pointer to the position on the array

または(更新)

ptr += 9; // pointer arithmetic using auxiliary pointer

"multi" は const 配列であるため、コンパイラは要素位置のローカリゼーションを既に "知っている" 必要があります。表示したいアイテム。より速く/より小さく/最適化されたアプローチは何ですか?

前もって感謝します。

4

5 に答える 5

8

それらはすべて同じ方法でコンパイルされます*(pointer_to_first_element + x + y).

于 2011-01-25T18:38:35.037 に答える
6

まずは

int multi[3][4];

const配列ではありません。constこの宣言には何もありません。

第二に、

int* ptr = *multi;

要素をptr指すようにしますmulti[0][0]。数値的には のmulti[0]アドレスと全体のアドレスと同じmultiですが、型が異なります。

第三に、

multi[3][1];

は定義上、

*(*(multi + 3) + 1);

したがって、パフォーマンスに正当な違いはありません。上記の内容とどのように関連しているかは明らかではありません。

第四に、

*ptr + 9;

「ポインター演算」はまったくありません。と同等です

multi[0][0] + 9;

これは通常の積分加算です。繰り返しますが、それが上記のこととどのように関連しているかは明らかではありません。

最後に、質問のタイトルは「定数ポインター配列または配列へのポインター」ですが、質問の実際のテキストにはどちらも表示されません。

于 2011-01-25T19:02:15.750 に答える
4

他の誰もそれを理解して維持することができないので、コードが投げられてもコードがどれほど速いかは問題ではありません。また、トリッキーなコードは、コンパイラがより良い最適化を行うのを妨げる場合があります。

例えば:

int main(void)
{
  int arr[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
  int *p = *arr; // == arr[0] == &arr[0][0]

  int x;

  x = arr[2][3];         // Straightforward array access
  x = *(*(arr+2)+3);     // Ugly pointer arithmetic
  x = *(ptr + 11);       // Slightly less ugly pointer arithmetic

  return 0;
}

上記を実行してgcc -c -g -Wa,-a,-ad > foo.lst、生成されたアセンブリとソースコードをインターリーブしました。

これがの翻訳ですx = arr[2][3];

movl      -16(%ebp), %eax     
movl      %eax, -8(%ebp)      

これがの翻訳ですx = *(*(arr+2)+3);

leal      -60(%ebp), %eax
addl      $44, %eax
movl      (%eax), %eax
movl      %eax, -8(%ebp)

そして最後に、x = *(ptr + 11);:の翻訳

movl      -12(%ebp), %eax
addl      $44, %eax
movl      (%eax), %eax
movl      %eax, -8(%ebp)

コンパイラの裏をかくことを試みないでください。これはもう1970年代ではありません。gccは、ユーザーに指示しなくても、配列アクセスを効率的に実行する方法を知っています。

アルゴリズムとデータ構造を調整し、コンパイラで最高の最適化設定を使用し(FWIW、3つのバージョンすべてで同じコードを生成する)、それでも失敗しない限り、このレベルでのパフォーマンスについて考える必要はありません。厳しいパフォーマンス要件を満たすため(この場合、正しい答えは通常、より高速なハードウェアを購入することです)。また、最初にプロファイラーを介してコードを実行し、実際のボトルネックを見つけることなく、 何も変更しないでください。測定、推測しないでください。 -O1

編集

当然、リテラル23が変数に置き換えられると、状況が変化します。その場合、*(ptr + offset);見栄えが良くなります。しかし、それほどではありません。そして、私はまだ、このレベルでは明快さがより重要であると主張します。

于 2011-01-25T20:54:58.363 に答える
2

a[i] つまり *(a+i)、実際には書くこともできi[a]、コンパイラーはそれを受け入れます。

*(ptr+i)とにかくptr[j][k]、単一の追加を行っているため(ptr[j][k]2が必要になる可能性があります)、理論よりもわずかに高速になる可能性があります。

于 2011-01-25T18:42:12.450 に答える
1

const配列がどこから来たのかはわかりませんが、議論のために、元の投稿にいくつかあったと仮定しましょう。

元のポスターではPCプログラミングについて明示的に言及されていなかったため、const配列と通常の配列は必ずしも同じ方法でコンパイルされるとは限りません。

組み込みシステムでは、const配列が真の不揮発性メモリ、つまり実際のROMを備えた組み込みアプリケーションに割り当てられている場合、const配列は非const配列よりも遅くなる可能性があります。速度の低下はROMのアクセス時間に関連しており、ハードウェア固有のものです。


ポインタ演算に関しては、それが配列にアクセスする唯一の方法です。C言語の配列構文は、コンパイラーが「シンタックスシュガー」と呼ぶものです。つまり、見た目だけです。次のような配列アクセス

arr [i]

コンパイラによって次のように変換されます

*(arr + i)

パフォーマンスと機能は同等です。

于 2011-01-25T20:57:19.173 に答える