#include <iostream>
using namespace std;
int main()
{
int arr[3] = { 10, 20, 30 };
cout << arr[-2] << endl;
cout << -2[arr] << endl;
return 0;
}
出力:
4196160
-30
ここでarr[-2]
は範囲外で無効であるため、未定義の動作が発生します。ただし、-2[arr]
は-30
と評価されます。どうして?
arr[-2]
は-2[arr]
と同等ではありませんか?
_-2[arr]
_は-(2[arr])
として解析されます。 C(およびC++では、オーバーロードを無視)では、_X[Y]
_の定義は*(X+Y)
です(これについての詳細は この質問 を参照してください)。つまり、_2[arr]
_は_arr[2]
_と等しい。
コンパイラはこの式を解析します
-2
のような
unary_minus decimal_integer_literal
つまり、整数リテラルの定義には符号が含まれません。
順番に式
2[arr]
コンパイラによって後置式として解析されます。
後置式は単項式よりも優先順位が高くなります。したがって、この式
-2[arr]
と同等です
- ( 2[arr] )
したがって、後置式2[arr]
によって返される左辺値に単項マイナスが適用されます。
一方、あなたが書いた場合
int n = -2;
その後
n[arr]
この式は次と同等です
arr[-2]
_-2[arr]
_は-(2[arr])
と同等で、_-arr[2]
_と同等です。ただし、_(-2)[arr]
_は_arr[-2]
_と同等です。
これは、 E1 [E2]は(*((E1)+(E2))) と同一であるためです。
根本的な問題はoperator precedenceにあります。 C++では、_[]
_、つまり下付き演算子は、_-
_ unary_minus演算子よりも優先されます(多少優先されます)。
だから、人が書くとき、
_arr[-2]
_
コンパイラーは最初に_arr[]
_を実行し、次に_-
_を実行しますが、unary_minusは_[-2]
_の境界内に囲まれているため、式は一緒に分解されます。
の中に、
_-2[arr]
_
同じことが起こりますが、コンパイラは_2[]
_演算子を最初に_-
_演算子を実行するため、最終的には_(-2)[arr]
_ではなく-(2[arr])
になります
_arr[i]
_ _i[arr]
_と*(i+arr)
はすべて同じであるという概念を理解していることは正しいことです。それらはすべて同等の式です。
そのように書きたい場合は、_(-2)[arr]
_と書きます。確かに同じ値が得られます。
今後の参考のためにこれをチェックしてください: http://en.cppreference.com/w/cpp/language/operator_precedence