配列要素を参照するシンタックスバリエーション
C言語では、以下のシンタックスは、すべて'B'に展開される。
(文字列リテラル"ABCDE"の格納領域の先頭アドレスを、0x8048560と仮定します。)
# | syntax |
---|---|
1 | "ABCDE"[1] |
2 | ((char *)0x8048560)[1] |
3 | 1["ABCDE"] |
4 | (&"ABCDE")[0][1] |
5 | 0[(&"ABCDE")][1] |
- 式中の文字列リテラルは、配列シンボルと同様の扱いを受ける。つまり、配列の先頭要素へのポインタに展開される。array[i]は、*(array+i)に展開されることも同様。ただし、間接演算子*や添字で間接参照しても、左辺値にはなり得ない。
- アドレスを即値指定もできるが、参照先のデータ型(サイズ)が不明であるとアドレス計算ができないので、(char *)とキャストする必要がある(参照先がchar型であると伝える)。
- array[i]は*(array+i)に展開されるということは、i[array]は、*(i+array)に展開される。交換法則により、両者は同じ意味となる。
- アドレス演算子をつけることで、配列"ABCDE"へのポインタ('A'へのポインタではないことに注意)に展開される。(&"ABCDE")[0]は、*(&"ABCDE"+0) → *(&"ABCDE")と展開され、間接演算子*とアドレス演算子が打ち消しあうので、結局、"ABCDE"と同じである。これに[1]をつけると、No1と同じシンタックスとなる。
- No4の(&"ABCDE")と0を入れ替えただけなので、交換法則により、No4と同じ意味となる。
トリッキーなコードの主眼は、見た目の珍奇さよりも、「原理を理解しているか」であると思う。