おそらく安全ですが、絶対に安全であるとは限りません。
最近のほとんどのシステムでは、すべてのポインター (少なくともすべてのオブジェクト ポインター) は同じ表現を持ち、あるポインター型から別の型への変換は、表現を構成するビットを再解釈するだけです。しかし、C 標準はこれを保証していません。
char *p = malloc (sizeof (int));
これにより、データのバイトchar*
へのポインターが得られます (成功したと仮定します)。sizeof (int)
malloc()
int *q = (int *)p;
char*
これにより、ポインターがポインターに変換されint*
ます。int
は よりも大きいため、char
ポインタint*
が何を指すかを示すために必要な情報が少なくて済みます。たとえば、単語指向のマシンでは、int*
は単に単語を指しているかもしれませんが、char*
には単語ポインタと、それが指す単語内のどのバイトを示すオフセットが含まれている必要があります。(私は実際に、このように動作する Cray T90 というシステムで作業しました。) したがって、 からchar*
への変換では、int*
実際には情報が失われる可能性があります。
free (q);
free()
は 型の引数を取るため、void*
引数q
は暗黙的に から に変換さint*
れvoid*
ます。言語標準では、char*
ポインターをint*
に変換してから結果を に変換すると、を に直接void*
変換した場合と同じ結果が得られるという保証はありません。char*
void*
一方、 はmalloc()
常に、任意の型を指すように正しく配置されたポインターを返すため、int*
とchar*
が異なる表現を持つシステム上であっても、この特定のケースで問題が発生する可能性はほとんどありません。
したがって、コードは、使用する可能性のあるシステムで正しく動作することが事実上確実であり、おそらく見たことのないエキゾチックなシステムでも正しく動作する可能性が非常に高くなります。
それでも、( 型の) 元のポインター値を保存して に渡すことにより、正しいことを簡単に実証できるコードを作成することをお勧めします。コードがほぼ確実に安全であることを示すのに数段落のテキストが必要な場合は、仮定を単純化することで、長期的には労力を節約できる可能性があります。プログラムで他の何かがうまくいかない場合 (私を信じてください、何かが起こるでしょう)、心配する可能性のあるエラーの原因が 1 つ少なくなるのは良いことです。char*
free()
malloc()
コードのより大きな潜在的な問題は、成功したかどうかをチェックしないことです。そうしないと失敗するようなことは何もしません (変換とfree()
呼び出しの両方がヌル ポインターで問題ありません) が、割り当てたメモリを参照すると問題が発生する可能性があります。
アップデート:
コードが合法かどうかを尋ねました。あなたはそれがあなたがしていることをするための最良の方法であるかどうかを尋ねませんでした.
malloc()
結果を返します。このvoid*
結果は、代入によって任意のオブジェクトへのポインター型に暗黙的に変換できます。引数free()
を取ります。void*
それに渡すポインターからオブジェクトへの型の引数は、暗黙的に に変換されvoid*
ます。この往復変換 (void*
からsomething_else*
へvoid*
) は安全です。何らかの型パニング (同じデータのチャンクを 2 つの異なる型として解釈する) を行っていない限り、キャストは必要ありません。
それよりも:
char *p = malloc (sizeof (int));
int *q = (int *)p;
free (q);
あなたはただ書くことができます:
int *p = malloc(sizeof *p);
...
free(p);
sizeof *p
への引数での の使用に注意してくださいmalloc()
。p
これにより、その型を明示的に参照しなくても、指すもののサイズが得られます。誤って間違った型を使用するという問題を回避します。
double *oops = malloc(sizeof (int));
コンパイラはおそらく警告しません。