2650

この質問では、 の結果をキャストすべきではないというコメントが誰かから提案されました。つまり、私はこれを行う必要があります:malloc

int *sieve = malloc(sizeof(*sieve) * length);

それよりも:

int *sieve = (int *) malloc(sizeof(*sieve) * length);

なぜこれが当てはまるのでしょうか?

4

29 に答える 29

2415

TL;DR

int *sieve = (int *) malloc(sizeof(int) * length);

には 2 つの問題があります。キャストと、変数の代わりに型を sizeof の引数として使用していること。代わりに、次のようにします。

int *sieve = malloc(sizeof *sieve * length);

ロングバージョン

いいえ; 次の理由から、結果をキャストしません。

  • void *この場合、他のポインター型に自動的かつ安全に昇格されるため、不要です。
  • コードが煩雑になり、キャストが読みにくくなります (特にポインター型が長い場合)。
  • それはあなたに同じことを繰り返させますが、これは一般的に悪いことです。
  • を含めるのを忘れた場合、エラーを隠すことができます<stdlib.h>。これにより、クラッシュが発生する可能性があります (または、さらに悪いことに、コードのまったく異なる部分でかなり後になるまでクラッシュが発生しません)。ポインターと整数のサイズが異なるとどうなるかを考えてみましょう。キャストによって警告を隠しているため、返されたアドレスの一部が失われる可能性があります。注: C99 以降、暗黙の関数は C から削除されました。宣言されていない関数が を返すという自動的な仮定がないため、この点はもはや関係ありませんint

明確にするために、「キャストする必要はない」ではなく、「キャストしない」と言ったことに注意してください。私の意見では、たとえ正しく理解できたとしても、キャストを含めるのは失敗です。それを行うメリットはまったくありませんが、多くの潜在的なリスクがあり、キャストを含めることは、リスクについて知らないことを示しています.

また、コメンテーターが指摘しているように、上記は C++ ではなくストレート C について述べていることに注意してください。私は、C と C++ は別々の言語であると固く信じています。

さらに追加すると、コードは型情報 ( int) を不必要に繰り返し、エラーを引き起こす可能性があります。戻り値を格納するために使用されているポインターを逆参照して、2 つを一緒に "ロック" することをお勧めします。

int *sieve = malloc(length * sizeof *sieve);

これlengthにより、視認性を高めるために も前面に移動し、冗長な括弧をsizeof;で削除します。引数が型名の場合にのみ必要です。多くの人はこれを知らない (または無視している) ようで、コードが冗長になります。覚えておいてください:sizeofは関数ではありません! :)


lengthまれに前面に移動することで視認性向上する場合もありますが、一般的な場合は次のように記述した方がよいことにも注意が必要です。

int *sieve = malloc(sizeof *sieve * length);

この場合、最初のものを保持するsizeofことで、少なくともsize_t数学で乗算が行われることが保証されます。

比較:malloc(sizeof *sieve * length * width)対。malloc(length * width * sizeof *sieve)_ length * width_ width_lengthsize_t

于 2009-03-03T10:17:53.817 に答える
435

C では、 の戻り値をキャストする必要はありませんmalloc。によって返される void へのポインターmallocは、正しい型に自動的に変換されます。ただし、コードを C++ コンパイラでコンパイルする場合は、キャストが必要です。コミュニティの間で推奨される代替手段は、次を使用することです。

int *sieve = malloc(sizeof *sieve * length);

これにより、 の型を変更した場合でも、式の右辺を変更することを心配する必要がなくなりますsieve

人々が指摘したように、キャストは悪いです。特にポインターキャスト。

于 2009-03-03T10:17:21.433 に答える
386

You do cast, because:

  • It makes your code more portable between C and C++, and as SO experience shows, a great many programmers claim they are writing in C when they are really writing in C++ (or C plus local compiler extensions).
  • Failing to do so can hide an error: note all the SO examples of confusing when to write type * versus type **.
  • The idea that it keeps you from noticing you failed to #include an appropriate header file misses the forest for the trees. It's the same as saying "don't worry about the fact you failed to ask the compiler to complain about not seeing prototypes -- that pesky stdlib.h is the REAL important thing to remember!"
  • It forces an extra cognitive cross-check. It puts the (alleged) desired type right next to the arithmetic you're doing for the raw size of that variable. I bet you could do an SO study that shows that malloc() bugs are caught much faster when there's a cast. As with assertions, annotations that reveal intent decrease bugs.
  • Repeating yourself in a way that the machine can check is often a great idea. In fact, that's what an assertion is, and this use of cast is an assertion. Assertions are still the most general technique we have for getting code correct, since Turing came up with the idea so many years ago.
于 2013-02-14T16:15:37.000 に答える
113

voidC では、ポインターを他の種類のポインターに暗黙的に変換できるため、キャストは必要ありません。これを使用すると、何気ない観察者に、それが必要な何らかの理由があることを示唆する可能性があり、誤解を招く可能性があります。

于 2009-03-03T10:18:12.710 に答える
110

の結果をキャストしません。キャストするmallocと、コードが無意味に混乱するからです。

人々が結果をキャストする最も一般的な理由mallocは、C 言語がどのように機能するかがわからないためです。これは警告サインです。特定の言語メカニズムがどのように機能するかがわからない場合は推測しないでください。調べるか、Stack Overflow で質問してください。

いくつかのコメント:

  • void ポインターは、明示的なキャストなしで他のポインター型との間で変換できます (C11 6.3.2.3 および 6.5.16.1)。

  • void*ただし、C++ では、と別のポインター型の間の暗黙的なキャストは許可されません。したがって、C++ では、キャストは正しいはずです。ただし、C++ でプログラミングする場合は、and を使用newしないでmalloc()ください。また、C++ コンパイラを使用して C コードをコンパイルしないでください。

    同じソース コードで C と C++ の両方をサポートする必要がある場合は、コンパイラ スイッチを使用して違いをマークします。互換性がないため、両方の言語標準を同じコードで満たそうとしないでください。

  • ヘッダーをインクルードするのを忘れたために C コンパイラが関数を見つけられない場合、それに関するコンパイラ/リンカー エラーが発生します。したがって、<stdlib.h>大したことではないことを含めるのを忘れた場合、プログラムを構築することはできません。

  • 25 年以上前のバージョンの標準に準拠する古いコンパイラでは、インクルード<stdlib.h>を忘れると危険な動作が発生します。その古い標準では、目に見えるプロトタイプのない関数は、暗黙的に戻り値の型を に変換したためintです。結果を明示的にキャストすると、mallocこのバグが隠されます。

    しかし、それは本当に問題ではありません。25 年前のコンピューターを使用していないのに、なぜ 25 年前のコンパイラーを使用するのでしょうか?

于 2014-03-20T15:53:14.890 に答える
101

C では、 からvoid *他の (データ) ポインターへの暗黙的な変換が行われます。

于 2009-03-03T10:16:21.467 に答える
75

によって返される値をキャストするmalloc()必要はありませんが、誰も指摘していないように思われる点を 1 つ追加したいと思います。

昔、つまりANSI Cvoid *がポインタのジェネリック型として を提供する前は、char *がそのような使用法のための型でした。その場合、キャストはコンパイラの警告をシャットダウンできます。

参考:C FAQ

于 2013-06-09T17:31:35.053 に答える
57

私の経験を追加して、コンピューター工学を勉強している私は、C で書いているのを見た 2 人か 3 人の教授が常に malloc をキャストしていることがわかりますが、私が尋ねた人 (膨大な履歴書と C の理解を持って) は、それは絶対に不要であると私に言いましたが、絶対に具体的であり、学生を絶対に具体的であるという考え方に導くためだけに使用されていました。基本的に、キャストによって動作が変わることはありません。まさにその通りに実行され、メモリが割り当てられます。キャストしても影響はありません。同じメモリが得られます。誤って別のものにキャストしたとしても (そして何らかの形でコンパイラを回避したとしても)エラー) C は同じ方法でアクセスします。

編集:キャスティングには特定のポイントがあります。配列表記を使用する場合、生成されたコードは、次の要素の先頭に到達するために何個のメモリ位置を進めなければならないかを知る必要があります。これは、キャストによって実現されます。このようにして、double の場合は 8 バイト進み、int の場合は 4 バイト進む、などがわかります。したがって、ポインタ表記を使用しても効果がなく、配列表記では必要になります。

于 2014-03-28T18:21:31.837 に答える
56

mallocを返すため、 の結果をキャストすることは必須ではなくvoid*、 avoid*は任意のデータ型を指すことができます。

于 2013-02-07T22:22:34.110 に答える
40

これは、GNU C ライブラリ リファレンスマニュアルに記載されている内容です。

ISO C は必要に応じて型を別の型のポインターにmalloc自動的に変換するため、キャストなしで任意のポインター変数に結果を格納できます。void *ただし、代入演算子以外のコンテキストでは、またはコードを従来の C で実行する場合は、キャストが必要です。

実際、ISO C11 標準(p347) には次のように書かれています。

割り当てが成功した場合に返されるポインターは、基本的なアライメント要件を持つ任意の型のオブジェクトへのポインターに割り当てられるように適切にアライメントされ、割り当てられた空間内のそのようなオブジェクトまたはそのようなオブジェクトの配列にアクセスするために使用されます (スペースは明示的に割り当て解除されます)

于 2015-10-09T17:47:38.610 に答える
36

void ポインターは汎用オブジェクト ポインターであり、C は void ポインター型から他の型への暗黙的な変換をサポートしているため、明示的に型キャストする必要はありません。

ただし、暗黙的な変換をサポートしていない C++ プラットフォームで同じコードを完全に互換性を持たせて動作させたい場合は、型キャストを行う必要があるため、すべて使いやすさに依存します。

于 2014-07-13T06:42:25.510 に答える
31

返される型は void* であり、逆参照可能にするために目的の型のデータ ポインターにキャストできます。

于 2013-04-26T16:43:31.443 に答える
31

プログラミング言語とコンパイラに依存します。C で使用する場合mallocは、自動的に型キャストされるため、型キャストする必要はありません。ただし、C++ を使用している場合は、型mallocを返すため、型キャストする必要がありますvoid*

于 2014-03-17T13:16:41.423 に答える
30

C 言語では、void ポインターを任意のポインターに割り当てることができるため、型キャストを使用しないでください。「タイプ セーフ」な割り当てが必要な場合は、C プロジェクトで常に使用する次のマクロ関数をお勧めします。

#include <stdlib.h>
#define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr))
#define NEW(ptr) NEW_ARRAY((ptr), 1)

これらが整っていれば、簡単に言うことができます

NEW_ARRAY(sieve, length);

非動的配列の場合、3 番目に必要な関数マクロは次のとおりです。

#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])

これにより、配列ループがより安全で便利になります。

int i, a[100];

for (i = 0; i < LEN(a); i++) {
   ...
}
于 2015-09-04T11:52:04.793 に答える
21

GCC と Clang に慣れている人は甘やかされてしまいます。それほど良いことばかりではありません。

私は何年もの間、私が使用しなければならなかった驚くほど古いコンパイラーにかなり恐怖を感じてきました。多くの場合、企業や管理者はコンパイラーの変更に対して非常に保守的なアプローチを採用し、新しいコンパイラー (標準への準拠とコードの最適化が改善されたもの) が自社のシステムで機能するかどうかをテストすることさえしません。作業中の開発者にとっての実際の現実は、コーディング中にベースをカバーする必要があるということです。残念ながら、コードに適用されるコンパイラを制御できない場合は、malloc をキャストすることをお勧めします。

また、多くの組織が独自のコーディング標準を適用し、それが定義されている場合はそれに従う方法を人々が採用することをお勧めします。明示的なガイダンスがない場合、私は標準への奴隷的な順守よりも、どこでもコンパイルできる可能性が最も高い傾向にあります。

現在の基準では必要ないという議論は非常に有効です。しかし、その議論は現実世界の実用性を省いています。私たちは、当時の標準だけに支配されている世界ではなく、私が「ローカル マネジメントの現実領域」と呼んでいる実用性に支配されている世界でコーディングを行っています。そして、それは時空がかつてないほど曲がってねじれています。:-)

YMMV。

私は malloc をキャストすることを防御操作と考える傾向があります。きれいでも完璧でもありませんが、一般的に安全です。(正直なところ、 stdlib.h を含めていない場合は、malloc をキャストするよりもはるかに多くの問題が発生します!)。

于 2015-12-04T17:27:54.660 に答える
20

この質問は意見に基づく悪用の対象です。

時々、次のようなコメントに気づきます。

malloc の結果をキャストしない

また

malloc の結果をキャストしない理由

OPがキャストを使用する質問について。コメント自体には、この質問へのハイパーリンクが含まれています。

それは、あらゆる意味で不適切であり、不正確でもあります。それが本当に自分自身のコーディングスタイルの問題である場合、正しいことも間違っていることもありません。


なぜこうなった?

それは次の 2 つの理由に基づいています。

  1. この質問は確かに意見に基づいています。技術的には、質問は数年前に意見に基づくものとしてクローズされるべきでした。「すべき」または「すべきでないか」または同等の「すべきか」または「すべきではないか」という質問では、自分の意見の態度がなければ、集中して答えることができません。ここでよく示されているように、質問を閉じる理由の 1 つは、「意見に基づく回答につながる可能性がある」ためです。

  2. 多くの回答 ( @unwindの最も明白で受け入れられている回答を含む) は、完全にまたはほぼ完全に意見に基づいています (キャストを行ったり、自分自身を繰り返したりする場合にコードに追加される不思議な「混乱」は悪いことです)。キャストを省略する明確で集中的な傾向。彼らは片側のキャストの冗長性について議論していますが、さらに悪いことに、プログラミング自体のバグ/失敗によって引き起こされたバグを解決することについても議論しています-使用したい場合はそうではありません.#include <stdlib.h>malloc()


議論されたいくつかの点について、私の個人的な意見は控えて、本当の見方を示したいと思います。特にいくつかの点に注意する必要があります。

  1. 自分の意見に陥りやすいこのような質問には、中立的な賛否両論の答えが必要です。短所や長所だけではありません。

    長所と短所の概要は、この回答に記載されています。

    https://stackoverflow.com/a/33047365/12139179

    (これまでのところ、これが最良の答えであると個人的に考えています。)


  1. キャストを省略した理由のほとんどは、キャストがバグを隠している可能性があることです。

    この質問に示されているように、誰かがmalloc()返す暗黙の宣言を使用している場合int(暗黙の関数はC99以降標準から削除されています)およびsizeof(int) != sizeof(int*)

    このコードが 64 ビット アーキテクチャでは segfault になるのに、32 ビットでは問題なく動作するのはなぜですか?

    キャストはバグを隠します。

    これは事実ですが、キャストの省略は、さらに大きなバグに対する前向きな解決策に過ぎないため、ストーリーの半分しか示していませstdlib.hmalloc()

    これは決して深刻な問題ではありません.

    1. C99 以上に準拠したコンパイラを使用する (これは推奨されており、必須である必要があります)。

    2. stdlib.hコードで使用したいときに ,を含めるのを忘れるほど欠席することはありませんmalloc()。これはそれ自体が大きなバグです。


  1. C++ ではキャストが義務付けられているため、C コードの C++ 準拠について議論する人もいます。

    まず、一般的に言うと、C++ コンパイラを使用して C コードをコンパイルすることは、適切な方法ではありません。

    実際、C と C++ は、セマンティクスが異なる 2 つの完全に異なる言語です。

    ただし、C コードを C++ に準拠させたい、またはその必要がある場合、またはその逆の場合は、キャストの代わりにコンパイラ スイッチを使用します。

    キャストは冗長または有害でさえあると宣言される傾向があるため、キャストが有用または必要でさえある正当な理由を示すこれらの質問に焦点を当てたいと思います。


  1. ほとんどの場合、ほとんどの場合ではありませんが、割り当てられたポインターの型 (およびそれに伴うキャストの型) が変更された場合、キャストは有益ではない可能性があります。次に、すべてのキャストも維持/変更する必要があります。コードにメモリ管理関数の呼び出しが数千ある場合、これは実際に要約され、メンテナンス効率が低下する可能性があります。

概要:

実際には、割り当てられたポインターが基本的なアラインメント要件のオブジェクト (ほとんどのオブジェクトを含む) を指している場合、キャストは C 標準 (ANSI-C (C89/C90) 以降) に従って冗長です。

この場合、ポインターは自動的に整列されるため、キャストを行う必要はありません。

「aligned_alloc、calloc、malloc、および realloc 関数の連続呼び出しによって割り当てられるストレージの順序と連続性は指定されていません。割り当てが成功した場合に返されるポインターは、任意の型のオブジェクトへのポインターに割り当てられるように適切に整列されます。基本的なアライメント要件であり、割り当てられたスペース内のそのようなオブジェクトまたはそのようなオブジェクトの配列にアクセスするために使用されます (スペースが明示的に割り当て解除されるまで)。」

出典: C18、§7.22.3/1


基本的なアラインメントは、以下の有効なアラインメントです_Alignof (max_align_t)。基本的なアラインメントは、すべてのストレージ期間のオブジェクトの実装によってサポートされます。次のタイプのアラインメント要件は、基本的なアラインメントです。

— すべてのアトミック、修飾、または非修飾の基本型。

— すべてのアトミック、修飾、または非修飾の列挙型。

— すべてのアトミック、修飾、または非修飾ポインター型。

— 要素型に基本的なアラインメント要件があるすべての配列型; 57)

- 完全なオブジェクトタイプとして箇条 7 で指定されたすべてのタイプ。

— すべての要素が基本アラインメント要件を持つ型を持ち、基本アラインメントではないアラインメントを指定するアラインメント指定子を要素に持たないすべての構造体型または共用体型。

  1. 6.2.1 で指定されているように、後の宣言は前の宣言を隠す可能性があります。」

出典: C18、§6.2.8/2

ただし、拡張アラインメント要件の実装定義オブジェクトにメモリを割り当てる場合は、キャストが必要になります。

拡張アラインメントは、 より大きいアラインメントで表され_Alignof (max_align_t)ます。拡張アラインメントがサポートされているかどうか、およびそれらがサポートされているストレージ期間は実装定義です。拡張アラインメント要件を持つタイプは、オーバー アライン タイプです。

ソース。C18、§6.2.8/3

他のすべては、特定のユースケースと自分の意見の問題です。

教育の仕方には気をつけてください。

最初にこれまでに行われたすべての回答を注意深く読み(失敗を指摘する可能性のあるコメントも) malloc()、特定のケースでの結果をキャストする場合、またはキャストしない場合は、独自の意見を構築することをお勧めします。

ご注意ください:

その質問には正解も不正解もありません。それはスタイルの問題であり、どちらを選択するかはあなた自身が決めることです (もちろん、教育や仕事によって強制されない場合)。だまされないように注意してください


最後のメモ: 私は最近、この質問を意見に基づくものとして閉じることに投票しました。閉鎖/再開の特権をお持ちでしたら、ぜひそうしていただきたいと思います。

于 2020-06-12T19:20:34.013 に答える
17

私がキャストを挿入したのは、型システムの醜い穴が承認されていないことを示すためだけです。これにより、次のスニペットなどのコードを診断せずにコンパイルできますが、不適切な変換を引き起こすためにキャストが使用されていません。

double d;
void *p = &d;
int *q = p;

それが存在しないことを望みます (そして、C++ には存在しません) ので、キャストします。それは私の好みと私のプログラミング方針を表しています。私はポインターをキャストするだけでなく、効果的に投票を行い、愚かな悪魔を追い出します. 私が実際に 愚かさを追い出すことができない場合は、少なくとも抗議のジェスチャーでそうしたいという願望を表明させてください.

実際には、mallocを返す関数でラップ (および友人)をラップunsigned char *し、基本的にvoid *コードで使用しないことをお勧めします。任意のオブジェクトへの一般的なポインターが必要な場合は、char *またはunsigned char *を使用し、両方向にキャストします。おそらく、満足できる唯一のリラクゼーションは、キャストなしのような関数を使用するmemsetことmemcpyです。

キャストと C++ の互換性については、C と C++ の両方としてコンパイルされるようにコードを記述した場合 (この場合、以外のものに代入するときにの戻り値キャストする必要があります)、非常に役立つことができます。 C++ としてコンパイルする場合は C++ スタイルのキャストに変換されますが、C としてコンパイルする場合は C キャストに変換されます。mallocvoid *

/* In a header somewhere */
#ifdef __cplusplus
#define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR))
#define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR))
#define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR))
#else
#define strip_qual(TYPE, EXPR) ((TYPE) (EXPR))
#define convert(TYPE, EXPR) ((TYPE) (EXPR))
#define coerce(TYPE, EXPR) ((TYPE) (EXPR))
#endif

これらのマクロに準拠している場合grepは、コード ベースでこれらの識別子を検索するだけで、すべてのキャストがどこにあるかが表示されるため、それらのいずれかが正しくないかどうかを確認できます。

その後、定期的に C++ でコードをコンパイルすると、適切なキャストの使用が強制されます。たとえば、strip_qual単にconstorを削除するために を使用しvolatileているが、型変換が含まれるようにプログラムが変更された場合、診断が表示され、目的の変換を得るためにキャストの組み合わせを使用する必要があります。

これらのマクロを順守するのに役立つように、GNU C++ (C ではありません!) コンパイラには美しい機能があります。それは、C スタイルのキャストのすべての発生に対して生成されるオプションの診断です。

     -Wold-style-cast (C++ および Objective-C++ のみ)
         非 void 型への古いスタイル (C スタイル) のキャストが使用されている場合に警告する
         C++ プログラム内。新しいスタイルのキャスト (dynamic_cast、
         static_cast、reinterpret_cast、const_cast) は脆弱性が低い
         意図しない効果が得られ、検索がはるかに簡単になります。

C コードが C++ としてコンパイルされる場合、このオプションを使用して、コードに忍び込む可能性-Wold-style-castのあるキャスト構文のすべての出現箇所を見つけ、上記のマクロ (または(type)必要に応じて組み合わせる)。

この変換の扱いは、「クリーン C」で作業するための単一の最大のスタンドアロンの技術的正当化です: C と C++ の方言を組み合わせたものであり、これにより、 の戻り値をキャストすることが技術的に正当化されますmalloc

于 2016-03-30T00:23:45.463 に答える
16

可能な限り C でプログラミングするときに行う最善の方法は次のとおりです。

  1. すべての警告をオンにして C コンパイラを使用してプログラムをコンパイルし、-Wallすべてのエラーと警告を修正します。
  2. として宣言された変数がないことを確認してくださいauto
  3. 次に、C++ コンパイラを使用してコンパイルし-Wallます-std=c++11。すべてのエラーと警告を修正します。
  4. もう一度 C コンパイラを使用してコンパイルします。これで、プログラムは警告なしでコンパイルされ、含まれるバグが少なくなります。

この手順により、C++ の厳密な型チェックを利用できるため、バグの数を減らすことができます。特に、この手順では、含めることを強制されますstdlib.h

mallocこのスコープ内で宣言されていませんでした

また、結果をキャストするように強制するか、mallocまたは取得します

void*からへの無効な変換T*

またはあなたのターゲットタイプが何であれ。

私が見つけたC++の代わりにCで書くことの唯一の利点は

  1. C には明確に指定された ABI がある
  2. C++ はより多くのコードを生成する可能性があります [例外、RTTI、テンプレート、ランタイムポリモーフィズム]

C に共通のサブセットを静的ポリモーフィック機能と一緒に使用すると、理想的なケースでは 2 番目の短所がなくなることに注意してください。

C++ の厳密な規則が不便だと思う人のために、C++11 の機能を推論された型で使用できます。

auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...
于 2015-06-12T15:23:56.197 に答える
14

キャストは、C++ ではなく C++ のみを対象としています。C++ コンパイラを使用している場合は、C コンパイラに変更することをお勧めします。

于 2015-09-10T15:58:49.030 に答える
10

void ポインターの背後にある概念は、malloc が void を返す理由である任意のデータ型にキャストできるということです。また、自動型キャストにも注意する必要があります。したがって、ポインターをキャストする必要はありますが、必須ではありません。コードをきれいに保ち、デバッグに役立ちます

于 2015-07-29T05:53:42.437 に答える
9
  1. 他の人が述べたように、C では必要ありませんが、C++ では必要です。

  2. キャストを含めると、C プログラムまたは関数を C++ としてコンパイルできる場合があります。

  3. void * は自動的かつ安全に他のポインタ型に昇格されるため、C では不要です。

  4. ただし、キャストすると、 stdlib.hを含めるのを忘れた場合にエラーが隠される可能性があり ます。これにより、クラッシュが発生する可能性があります (または、さらに悪いことに、コードのまったく別の部分でかなり後になるまでクラッシュが発生しません)。

    stdlib.hに含まれているため、malloc のプロトタイプが見つかります。malloc のプロトタイプがない場合、標準では、C コンパイラが malloc が int を返すと想定する必要があります。キャストがない場合、この整数がポインターに割り当てられると警告が発行されます。ただし、キャストを使用すると、この警告は生成されず、バグが隠されます。

于 2016-11-08T10:09:54.020 に答える
1

の主な問題は、適切なサイズmallocを取得することです。

返されるメモリの形式malloc()untypedであり、単純なキャストにより魔法のように有効な型を取得することはありません。

どちらのアプローチも問題なく、どちらを選択するかはプログラマーの意図に依存すると思います。

  1. typeにメモリを割り当てる場合は、キャストを使用します。

ptr = (T*)malloc(sizeof(T));

  1. 特定のポインタにメモリを割り当てる場合は、キャストを使用しないでください。

ptr = malloc(sizeof *ptr);

広告 1

最初のメソッドは、特定の型にメモリを割り当て、それをキャストして正しいポインタに割り当てられるようにすることで、正しいサイズを保証します。の型が正しくない場合ptr、コンパイラは警告/エラーを発行します。の型ptrが変更された場合、コンパイラはコードのリファクタリングが必要な場所を示します。

newさらに、最初のメソッドは、C++ の operator に似たマクロに結合できます。

#define NEW(T) ((T*)malloc(sizeof(T)))
...
ptr = NEW(T);

さらに、このメソッドは の場合ptrに機能しvoid*ます。

広告 2

2 番目のメソッドは型を気にせず、ポインターの型から取得することで正しいサイズを保証します。この方法の主な利点は、 のタイプptrが変更されるたびにストレージ サイズが自動的に調整されることです。リファクタリング時の時間 (またはエラー) を節約できます。

不利な点は、そうである場合にこの方法が機能しないことですptrvoid*、それは良いこととして認識される可能性があります。また、C++ では機能しないため、C++ プログラムで使用されるヘッダーのインライン関数では使用しないでください。

個人的には、2番目のオプションを好みます。

于 2022-01-17T11:11:40.473 に答える
0

私にとって、ここでの持ち帰りと結論はmalloc、Cでのキャストはまったく必要ないということですが、キャストしても、要求された祝福されたメモリスペースが引き続き割り当てられるため、malloc影響はありません。mallocもう1つの持ち帰りは、人々がキャストを行う理由または理由の1つであり、これは、CまたはC ++で同じプログラムをコンパイルできるようにすることです。

他にも理由があるかもしれませんが、遅かれ早かれ深刻なトラブルに巻き込まれることはほぼ確実です。

于 2020-03-05T15:56:20.197 に答える