すべてのポインターは特定の型です。void*
任意のオブジェクト型を指すことができる特別なジェネリック ポインター型がありますvoid*
が、逆参照する前に特定のポインター型に変換する必要があります。(関数ポインタ型は無視しています。)
ポインター値をあるポインター型から別の型に変換できます。ほとんどの場合、ポインタを からfoo*
に変換し、元の値bar*
に戻すとfoo*
、元の値が得られますが、実際にはすべての場合で保証されているわけではありません。
type のポインターが typeのオブジェクトを指すようにすることはできますが、(a) 通常は悪い考えであり、(b) 場合によっては機能しない可能性があります (たとえば、ターゲットの型とのサイズまたは配置が異なる場合)。要件)。foo*
bar
foo
bar
次のようなことで逃げることができます:
int n = 42;
char *p = (char*)&n;
--p
を指すようになりますが、 の値は得られません。の最初のバイトの値が として得られます。n
*p
n
n
char
ポインター演算の異なる動作は、異なるポインター型を持つ理由の一部にすぎません。主にタイプセーフに関するものです。type のポインターがある場合int*
、(安全でないことをしていない限り) それが実際にint
オブジェクトを指していることを合理的に確信できます。そして、それを別の型のオブジェクトとして扱おうとすると、コンパイラはそれについて文句を言うでしょう。
基本的に、他の異なる型があるのと同じ理由で、異なるポインター型があります。そのため、コンパイラーの助けを借りて、各オブジェクトに格納されている値の種類を追跡できます。
(型指定されていないジェネリック ポインターしか持たない言語がありました。そのような言語では、ある型の値を格納し、別の型であるかのように誤ってアクセスするなど、型エラーを回避することがより困難になります。)