型の compatibility とポインタ演算 長谷川啓 2018.10.11
型の compatibility 厳密な定義は、規格を参考にしてください。ざっくりというと ⇔ 型 T1 と型 T2 が compatible ⇔ extern T1 x; extern T2 x; がエラーではない。
配列の compatibility typedef int T1[]; typedef int T2[10]; extern T1 x; はエラーではないので、 型 int [] と型 int [10] は compatible
関数の compatibility typedef void T1(int (*)(int), double (*)[]); typedef void T2(int (*)(), double (*)[2]); typedef void T3(); extern T1 x; extern T2 x; extern T3 x; はエラーではないので 型 void (int (*)(int), double (*)[])、型 void (int (*)(), double (*)[2]) 、型 void () は互いに compatible
タグ型の compatibility struct S; extern struct S x; // 不完全型 struct S { int a; }; extern struct S x; // 完全型 はエラーではないので 不完全型 struct S と完全型 struct S は compatible
ポインタの compatibility 型 T1 と型 T2 が compatible ⇔ extern T1 *x; がエラーではない。
ポインタ演算の大原則 2 つのポインタの指す型 T1, T2 から型修飾子を取り去った型 T’1, T’2 が compatible である場合、同一のビット表現とアラインメントをもつ。 int* p と const int* q とでビット表現、アラインメントが同じでなくてはならないということ。 だから、int* p と const int* q とで比較、代入等が成立する。ただし p = q は修飾子の意味でエラー。 int** p2 と const int** q2 に対して演算は定義されていない、すなわちエラーである。 T1 は int*, T2 は const int* で、 T’1, T’2 はそれぞれ T1, T2 と同じだが、int* と const int* は compatible ではないから。
ポインタ間の演算 ~ 大原則が適用される p – q p < q, p > q, p <= q, p >= q void* や 0 との比較もできる expr ? p : q void* や 0 でも OK p = q