4

別の型にキャストされたポインタをfree()しても大丈夫かどうか知りたいです。たとえば、私がこれを行う場合:

char *p = malloc (sizeof (int));
int *q = (int *)p;
free (q);

gcc(-Wall)で警告が表示されません。

Linuxの場合、freeのマニュアルページには、malloc()、calloc()、またはrealloc()によって返されないポインターでfreeを呼び出すことは違法であると記載されています。しかし、ポインタがその間に別の型にキャストされた場合はどうなりますか?

C標準では同じサイズの異なるポインター型(int*とchar*など)は必要ないことを読んだので、これを尋ねます。どちらもvoid *に変換可能である必要があるため、これがどのように可能か理解できません。 malloc/free関数を呼び出すため。

上記のコードは合法ですか?

4

4 に答える 4

6

おそらく安全ですが、絶対に安全であるとは限りませ

最近のほとんどのシステムでは、すべてのポインター (少なくともすべてのオブジェクト ポインター) は同じ表現を持ち、あるポインター型から別の型への変換は、表現を構成するビットを再解釈するだけです。しかし、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));

コンパイラはおそらく警告しません。

于 2012-10-02T22:47:42.250 に答える
3

はい、ポインタは変更されません。キャストは、コンパイラがビットの束を解釈する方法にすぎません。

編集:malloc呼び出しは、メモリ内のアドレス、つまり32(または64)ビット数を返します。キャストは、そのアドレスに格納されている値をどのように解釈するか(float、整数、文字列など)、およびアドレスで算術演算を行う場合、ユニットがステップインする必要がある大きさをコンパイラーに指示するだけです。

于 2012-10-02T22:43:49.767 に答える
3

はい、それは合法です。free()voidポインタ()を取るvoid*ので、タイプは関係ありません。渡されたポインタが返される限り、malloc/realloc/callocそれは有効です。

于 2012-10-02T22:46:08.393 に答える
0

コードは合法ですが、必須ではありません。ポインタはデータが格納されているアドレスのみを指しているため、スペースを割り当てたり、後で解放したりする必要はありません。

于 2012-10-02T22:44:14.440 に答える