Cで、ポインターを解放する前にキャストする人がいるのはなぜですか?


167

私は古いコードベースで作業しており、free()のほとんどすべての呼び出しはその引数にキャストを使用します。例えば、

free((float *)velocity);
free((float *)acceleration);
free((char *)label);

ここで、各ポインターは対応する(および一致する)タイプです。私はこれをする意味が全くないと思います。これは非常に古いコードなので、K&Rなのかどうか疑問に思います。もしそうなら、私は実際にこれを必要としたかもしれない古いコンパイラをサポートしたいので、それらを削除したくありません。

これらのキャストを使用する技術的な理由はありますか?私はそれらを使用する実用的な理由の多くを見さえしません。解放する直前にデータ型を思い出すポイントは何ですか?

編集:この質問は他の質問の重複ではありません。もう1つの質問は、この質問の特別なケースです。近い投票者がすべての回答を読んでいれば明らかです。

Colophon:「const答え」にチェックマークを付けています。これは、これを行う必要があるのは本当の理由です。ただし、それがANSI Cより前のカスタムであることについての回答(少なくとも一部のプログラマの間で)が、私の場合に使用された理由のようです。ここには多くの人々による良い点がたくさんあります。あなたの貢献に感謝します。


13
「データ型を解放する直前に思い出す意味は何ですか?」解放されるメモリの量を知っているのでしょうか?
m0skit0

12
@Codorコンパイラは割り当て解除を行わず、オペレーティングシステムが行います。
m0skit0

20
@ m0skit0 「解放されるメモリの量を知っているかもしれませんか?」タイプは、解放する量を知る必要はありません。その理由だけでキャストは悪いコーディングです。
user694733

9
@ m0skit0読みやすさのためにキャストすると、コーディングが不適切になります。これは、キャストによって型の解釈方法が変わり、重大なエラーが隠される可能性があるためです。読みやすさが必要な場合は、コメントの方が優れています。
user694733

66
恐竜が地球を歩き、プログラミングの本を書いた古代の時代にはvoid*、先行標準のC にはなく、Cだけがあったと思いますchar*。したがって、考古学的な調査結果から、パラメーターをfree()にキャストするコードが明らかになった場合、それはその期間からのものか、その期間の生き物によって書かれたもののどちらかであると思います。ただし、これに関する情報源が見つからないため、回答を差し控えます。
ランディン

回答:


171

ポインターがの場合、コンパイラー警告を解決するためにキャストが必要になる場合がありますconst。以下は、freeの引数をキャストせずに警告を発生させるコードの例です。

const float* velocity = malloc(2*sizeof(float));
free(velocity);

そしてコンパイラ(gcc 4.8.3)はこう言っています:

main.c: In function main’:
main.c:9:5: warning: passing argument 1 of free discards const qualifier from pointer target type [enabled by default]
     free(velocity);
     ^
In file included from main.c:2:0:
/usr/include/stdlib.h:482:13: note: expected void *’ but argument is of type const float *’
 extern void free (void *__ptr) __THROW;

あなたが使うならfree((float*) velocity);コンパイラは文句を言うのをやめます。


2
float*解放する前に誰かがキャストする理由を説明しない@ m0skit0 。free((void *)velocity);gcc 4.8.3で試しました。もちろん、古代のコンパイラーでは機能しません
Manos Nikolaidis

54
しかし、なぜ定数メモリを動的に割り当てる必要があるのでしょうか?あなたはそれを使用することはできません!
Nils_M

33
@Nils_Mそれはポイントを作る簡単な例です。関数の実際のコードで私が行ったことは、非constメモリを割り当て、値を割り当て、constポインタにキャストしてそれを返すことです。ここで、誰かが解放しなければならない、事前に割り当てられたconstメモリへのポインタがあります。
Manos Nikolaidis

2
:「これらのサブルーチンは、* stringValuePによってポイントされる、新しくmallocされたメモリに文字列を返します。これは、最終的に解放する必要があります。* stringValuePがconstへのポインターであるため、メモリを解放するために使用するOS関数が、定数でないものへのポインターを引数として取るように宣言されることがあります。
Carsten S

3
エラー、関数がconst char *p引数として取り、それを解放する場合、freeを呼び出す前にキャストpするのは正しいことではありませんchar*。それは変更され、それに応じて宣言される必要があるconst char *pので、最初からそれを受け入れる *pと宣言しないことです。(そして、constへのポインターの代わりにconstポインターが必要な場合は、キャストする必要int *const pありません。実際には正当であり、キャストなしで問題なく機能します。)
Ray

59

先行標準のCにはvoid*しかなかったchar*ため、渡されたすべてのパラメーターをキャストする必要がありました。古代のCコードに出会った場合、そのようなキャストを見つけるかもしれません。

リファレンスと同様の質問

最初のC標準がリリースされたとき、mallocとfreeのプロトタイプが持つから変更char*void*、彼らはまだ今日を持っていること。

そしてもちろん、標準Cでは、そのようなキャストは不必要で読みやすさを損なうだけです。


23
しかし、なぜあなたは引数をfreeすでにある型にキャストするのでしょうか?
jwodder

4
@chux先行標準の問題はそれだけです。何に対しても義務はありません。それが彼らが持っていた唯一のものだったので、人々はちょうどキヤノンのためのK&R本を指摘しました。また、K&R 2nd Editionのいくつかの例からわかるように、K&R自体はfree、標準のCでパラメーターのキャストがどのように機能するかについて混乱しています(キャストする必要はありません)。私は第1版を読んでいないので、80年代の標準前の時代にも混乱していたかどうかはわかりません。
ランディン

7
先行標準のCにははありませんでしたがvoid*、関数プロトタイプもなかったためfree、K&Rでも引数のキャストは不要でした(すべてのデータポインター型が同じ表現を使用していると仮定)。
Ian Abbott

6
すでにコメントで述べられているいくつかの理由から、私はこの答えが意味をなさないと思います。
R .. GitHub ICE HELPING ICEを停止する

4
この答えが実際に関連するものにどのように答えるかはわかりません。元の質問には、だけでなく、他の型へのキャストが含まれchar *ます。それなしの古いコンパイラではどういう意味voidですか?そのようなキャストは何を達成しますか?
AnT

34

キャストなしでfreeが失敗する例を次に示します。

volatile int* p = (volatile int*)malloc(5 * sizeof(int));
free(p);        // fail: warning C4090: 'function' : different 'volatile' qualifiers
free((int*)p);  // success :)
free((void*)p); // success :)

Cでは警告が表示されます(VS2012で警告が表示されます)。C ++ではエラーが発生します。

まれなケースはさておき、キャスティングはコードを膨らませるだけです...

編集: 私は失敗をデモしvoid*ないint*ようにキャストしました。暗黙的int*に変換されるのと同じように機能しますvoid*int*コードを追加しました。


質問に投稿されたコードでは、キャストがにはないことに注意してくださいvoid *、これだけにfloat *してchar *。これらのキャストは無関係なだけではなく、間違っています。
Andrew Henle

1
問題は実際にはその逆です。
m0skit0

1
答えがわかりません。どんな意味でfree(p)失敗するでしょうか?コンパイラエラーが発生しますか?
Codor、2015

1
これらは良い点です。同じことはconst、明らかに修飾子ポインターにも当てはまります。
Lundin、2015

2
volatileCが標準化されて以来、もはや存在していません。それはしていない C99で追加します。
R .. GitHub ICE HELPING ICEの停止

30

以前の理由:1.を使用することによりfree((sometype*) ptr)、ポインターがfree()呼び出しの一部と見なされる型についてコードが明示されます。明示的なキャストはfree()、が(do-it-yourself)に置き換えられた場合に役立ちますDIY_free()

#define free(ptr) DIY_free(ptr, sizeof (*ptr))

A DIY_free()は(特に)解放されたポインターの実行時分析を行う方法であり、特にデバッグモードではそうでした。多くの場合、これはと一緒に使用しDIY_malloc()て、センテンス、グローバルメモリ使用量などを追加します。私のグループは、より新しいツールが登場するまで何年もこの手法を使用していました。解放されたアイテムが元々割り当てられていたタイプにキャストされたことが義務付けられました。

  1. メモリの問題などを追跡するのに長い時間がかかることを考えると、型をfreeにキャストするような小さなトリックは、デバッグを検索して絞り込むのに役立ちます。

モダン:Manos Nikolaidis @@egurによって対処された回避constvolatile警告。私は3つの影響に注意してくださいだろうと思ったの修飾子を:、、と。constvolatilerestrict

[編集] @R ..コメントchar * restrict *rp2ごとに追加

void free_test(const char *cp, volatile char *vp, char * restrict rp, 
    char * restrict *rp2) {
  free(cp);  // warning
  free(vp);  // warning
  free(rp);  // OK
  free(rp2);  // warning
}

int main(void) {
  free_test(0,0,0,0);
  return 0;
}

3
restrict配置されているため、問題にはなりrpません-指定された型ではなくオブジェクトに影響します。代わりにがあったchar *restrict *rp場合、それは重要です。
R .. GitHub ICEのヘルプの停止

16

これは別の対立仮説です。

プログラムはC89より前に作成されたと言われています。つまり、のプロトタイプとの何らかの不一致を回避することはできませんfree。なぜなら、C89のようなものconstvoid *以前のものもなかっただけでなく、関数プロトタイプ C89に先立っ。 stdlib.hそれ自体が委員会の発明でした。システムヘッダーがfreeまったく宣言する必要がない場合、次のようになります。

extern free();  /* no `void` return type either! */

ここで重要なのは、関数プロトタイプがないため、コンパイラーが引数の型チェックを行わなかったことです。デフォルトの引数のプロモーション(可変引数の関数呼び出しにまだ適用されるものと同じもの)を適用しました。各呼び出しサイトでの引数を呼び出し先の期待に合わせる責任は、すべてプログラマーにあります。

ただし、これはfree、ほとんどのK&Rコンパイラで引数をキャストする必要があったことを意味するものではありません。のような機能

free_stuff(a, b, c)
    float *a;
    char *b;
    int *c;
{
    free(a);
    free(b);
    free(c);
}

正しくコンパイルされているはずです。したがって、ここにあるのは、異常な環境のバグのあるコンパイラに対処するために記述されたプログラムだと思います。たとえば、ポイントでキャストしない限りsizeof(float *) > sizeof(int)、コンパイラポインタに適切な呼び出し規約を使用しない環境呼び出しの。

私はそのような環境に気づいていませんが、それがなかったという意味ではありません。頭に浮かぶ可能性が最も高い候補は、1980年代初頭の8ビットおよび16ビットマイクロ向けの削減された「小さなC」コンパイラーです。また、初期のクレイズがこのような問題を抱えていたことを知って驚くこともありません。


1
前半は完全に同意します。そして後半は興味深く、もっともらしい推測です。
chux-モニカを2015年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.