C 標準は []
を定義します 演算子は次のとおりです:
a[b] == *(a + b)
したがって a[5]
次のように評価されます:
*(a + 5)
と 5[a]
次のように評価されます:
*(5 + a)
a
配列の最初の要素へのポインタです。 a[5]
5 要素の値です a
からさらに 、これは *(a + 5)
と同じです であり、小学校の数学から、それらが等しいことがわかっています (足し算は可換です)。
配列アクセスはポインターの観点から定義されているためです。 a[i]
*(a + i)
を意味するように定義されています 、可換です。
他の回答では何かが見落とされていると思います.
はい、p[i]
定義上、*(p+i)
と同等です 、これは (加算は交換可能であるため) *(i+p)
と同等です 、これ (再び、[]
の定義による) operator) は i[p]
と同等です .
(そして array[i]
で 、配列名は配列の最初の要素へのポインターに暗黙的に変換されます。)
しかし、この場合、足し算の可換性はそれほど明白ではありません。
両方のオペランドが同じ型である場合、または共通の型に昇格された異なる数値型であっても、可換性は完全に理にかなっています:x + y == y + x
.
しかし、この場合は、1 つのオペランドがポインターで、もう 1 つのオペランドが整数であるポインター演算について具体的に話しています。 (整数 + 整数は別の演算であり、ポインタ + ポインタはナンセンスです。)
+
の C 標準の説明 オペレーター (N1570 6.5.6) のコメント:
次のように簡単に言えます:
この場合、両方の i + p
と i[p]
C++ の用語では、オーバーロードされた +
のセットが 2 つあります。 大まかに次のように説明できる演算子:
pointer operator+(pointer p, integer i);
そして
pointer operator+(integer i, pointer p);
そのうち、本当に必要なのは最初の 1 つだけです。
では、なぜこのようになっているのでしょうか?
C++ はこの定義を C から継承し、C は B から取得しました (配列のインデックス付けの可換性は、1972 年の B へのユーザー リファレンスで明示的に言及されています)。BCPL から取得しました (1967 年のマニュアル)。以前の言語 (CPL? Algol?)
したがって、配列のインデックス付けは加算によって定義され、ポインターと整数の加算でさえ交換可能であるという考えは、何十年も前の C の祖先言語にまでさかのぼります。
これらの言語は、現代の C よりもはるかに型付けが厳しくありませんでした。特に、ポインターと整数の違いはしばしば無視されていました。 (初期の C プログラマーは、unsigned
の前に、ポインターを符号なし整数として使用することがありました。 キーワードが言語に追加されました。) したがって、オペランドの型が異なるために加算を非可換にするという考えは、おそらくこれらの言語の設計者には思いつかなかったでしょう。ユーザーが 2 つの「もの」を追加したい場合、それらの「もの」が整数、ポインター、またはその他のものであるかどうかにかかわらず、それを防ぐのは言語次第ではありませんでした。
そして何年にもわたって、そのルールを変更すると、既存のコードが壊れていました (ただし、1989 年の ANSI C 標準は良い機会だったかもしれません)。
C および/または C++ を変更して、ポインターを左側に、整数を右側に配置する必要があるようにすると、既存のコードが壊れる可能性がありますが、実際の表現力が失われることはありません。
これで arr[3]
になりました と 3[arr]
まったく同じことを意味しますが、後者の形式は IOCCC の外に出てはなりません。