でこの質問、誰かがで提案されているコメント、私がすべきことではないの結果キャストmalloc
すなわち、
int *sieve = malloc(sizeof(int) * length);
のではなく:
int *sieve = (int *) malloc(sizeof(int) * length);
これはなぜでしょうか?
NULL
。(それがおそらくC ++が導入された理由です。C++ではnullptr
暗黙のポインターキャストが許可されていません)
でこの質問、誰かがで提案されているコメント、私がすべきことではないの結果キャストmalloc
すなわち、
int *sieve = malloc(sizeof(int) * length);
のではなく:
int *sieve = (int *) malloc(sizeof(int) * length);
これはなぜでしょうか?
NULL
。(それがおそらくC ++が導入された理由です。C++ではnullptr
暗黙のポインターキャストが許可されていません)
回答:
いいえ ; 次の理由により、結果をキャストしません。
void *
この場合、自動的かつ安全に他のポインター型に昇格されるため、これは不要です。<stdlib.h>
。これにより、クラッシュが発生する可能性があります(さらに悪いことに、コードの完全に異なる一部の部分まではクラッシュしません)。ポインタと整数のサイズが異なる場合にどうなるかを考えます。次に、キャストによって警告を非表示にし、返されたアドレスの一部を失う可能性があります。注:C99以降、暗黙的な関数はCからなくなり、宣言されていない関数がを返すという自動仮定がないため、この点は関係ありませんint
。私は「あなたはキャストしていない」と述べたことを明確に、注意点としては、「あなたはしていないではない必要があるキャストに」。私の意見では、それが正しいとしても、キャストを含めるのは失敗です。それを行うだけの利点はありませんが、潜在的なリスクがたくさんあり、キャストを含めると、リスクについて知らないことがわかります。
また、コメンテーターが指摘するように、上記はC ++ではなくストレートCについて述べていることに注意してください。CとC ++は別々の言語であると私は強く信じています。
さらに追加すると、コードは不必要にタイプ情報(int
)を繰り返し、エラーを引き起こす可能性があります。戻り値を格納するために使用されているポインターを逆参照して、2つを「ロック」することをお勧めします。
int *sieve = malloc(length * sizeof *sieve);
これはまた、length
視認性を高めるためにを前に移動し、で余分な括弧を削除しsizeof
ます。これらは、引数が型名である場合にのみ必要です。多くの人はこれを知らない(または無視する)ようで、コードがより冗長になります。覚えておいてください:sizeof
は関数ではありません!:)
移動しながらlength
前にするともまれでは視認性を高める、1はまた、一般的なケースでは、それはのように式を記述する方が良いでなければならないことに注意を払う必要があります。
int *sieve = malloc(sizeof *sieve * length);
sizeof
この場合、最初を維持するため、乗算は少なくともsize_t
数学で行われます。
比較:malloc(sizeof *sieve * length * width)
vs malloc(length * width * sizeof *sieve)
. 2番目はlength * width
when width
をオーバーフローする可能性があり、length
より小さい型ですsize_t
。
int x = (int) 12;
物事を明確にするために行いますか?
(int)12
比較することはできません。12
は、int
キャストは何もしません。のretval malloc()
はvoid *
、キャストされたポインター型ではありません。(そうでない場合void *
、のアナロジーは誰も議論していない(int)12
ことになります(void*)malloc(…)
。)
Cでは、の戻り値をキャストする必要はありませんmalloc
。が返すvoidへのポインタmalloc
は、自動的に正しい型に変換されます。ただし、コードをC ++コンパイラでコンパイルする場合は、キャストが必要です。コミュニティの間で推奨される代替策は、以下を使用することです。
int *sieve = malloc(sizeof *sieve * length);
これにより、のタイプを変更した場合でも、式の右側を変更する必要がなくなりますsieve
。
キャストが悪いのは、人々が指摘しているようです。特にポインターキャスト。
malloc(length * sizeof *sieve)
それsizeof
は変数のように見えるようにすることを主張するでしょう-だから私malloc(length * sizeof(*sieve))
はもっと読みやすいと思います。
malloc(length * (sizeof *sieve))
まだ、より読みやすいです。私見では。
()
問題はさておき、提案されたスタイルが順序を入れ替えたことに注意してください。要素数がのようlength*width
に計算される場合を考慮し、sizeof
最初の場合は最初の式を維持して、少なくともsize_t
数学で乗算が行われることを保証します。比較malloc(sizeof( *ptr) * length * width)
対を malloc(length * width * sizeof (*ptr))
-第二がオーバーフローするlength*width
際にwidth,length
その小さいタイプがありますsize_t
。
malloc(sizeof *sieve * length)
static_cast>()
(またはreinterpret_cast<>()
)Cのどの方言とも互換性がありません
あなたがキャストするのは、
type *
対がtype **
。#include
適切なヘッダーファイルに失敗したことに気づかないようにするという考えは、木の森を見逃してしまいます。これは、「コンパイラーにプロトタイプが表示されないことについて文句を言うのに失敗したという事実について心配しないでください-その厄介なstdlib.hは、覚えておかなければならない本当に重要なことです!」malloc()
、キャストがあるとバグがはるかに早く検出されることを示すSOの調査を行うことができるでしょう。アサーションと同様に、意図を明らかにする注釈はバグを減らします。.c
/ .cpp
の両方としてコンパイルするファイルは、非常に便利ではありませんが、一つのケースは、C ++の追加されたthrow
C ++コンパイラでコンパイルするときのサポートを(ただし、return -1;
Cコンパイラ、または任意でコンパイルした場合)。
malloc
char **foo = malloc(3*sizeof(*foo));
foo[i] = calloc(101, sizeof(*(foo[i])));
unsigned char
struct Zebra *p; ... p=malloc(sizeof struct Zebra);
場合、mallocはpの型に関する情報の重複を回避できませんが、一方の型が変更されても他方の型が変更されない場合、コンパイラーもローカルコード検査も問題を検出しません。コードをに変更するp=(struct Zebra*)malloc(sizeof struct Zebra);
と、キャストタイプが一致しない場合、コンパイラーがp
他の人が述べたように、Cには必要ありませんが、C ++には必要です。CコードをC ++コンパイラでコンパイルする予定がある場合は、何らかの理由で、代わりに次のようなマクロを使用できます。
#ifdef __cplusplus
# define NEW(type, count) ((type *)calloc(count, sizeof(type)))
#else
# define NEW(type, count) (calloc(count, sizeof(type)))
#endif
そうすれば、非常にコンパクトな方法でそれを書くことができます:
int *sieve = NEW(int, 1);
CとC ++用にコンパイルされます。
new
ているので、C ++の定義に使ってみませんか?
new
する場合は使用する必要があり、使用するdelete
場合は使用malloc()
する必要がありますfree()
。それらを混ぜないでください。
NEW
、リソースがdelete
(またはDELETE
)を使用して返されることはないので、マクロを呼び出すことはおそらくお勧めできません。代わりに、名前を付けるMALLOC
かCALLOC
、この場合はもっとわかりやすくします。
ウィキペディアから:
キャストの利点
キャストを含めると、Cプログラムまたは関数をC ++としてコンパイルできる場合があります。
キャストでは、元々char *を返していた1989年より前のバージョンのmallocを使用できます。
キャストは、特にポインターがmalloc()呼び出しから遠く離れて宣言されている場合、宛先ポインターのタイプが変更された場合に、開発者が型サイズの不整合を特定するのに役立ちます(ただし、最近のコンパイラーおよび静的アナライザーは、キャストを必要とせずにそのような動作について警告できます)。
キャストの短所
ANSI C標準では、キャストは冗長です。
キャストを追加すると、ヘッダーを含めることができなくなる可能性があります stdlib.hます、mallocのプロトタイプが見つかりました。mallocのプロトタイプがない場合、標準では、Cコンパイラがmallocがintを返すことを前提としています。キャストがない場合、この整数がポインターに割り当てられると警告が発行されます。ただし、キャストでは、この警告は生成されず、バグを隠します。特定のアーキテクチャとデータモデル(64ビットシステムのLP64など、longとポインタが64ビットで、intが32ビット)では、暗黙的に宣言されたmallocが32を返すため、このエラーは実際には未定義の動作を引き起こす可能性があります。実際に定義された関数は64ビット値を返しますが、ビット値。呼び出し規約とメモリレイアウトによっては、スタックスマッシュが発生する可能性があります。この問題は、最新のコンパイラでは見過ごされがちですが、宣言されていない関数が使用されたという警告を一律に生成するため、警告が表示されます。たとえば、GCCのデフォルトの動作では、キャストが存在するかどうかに関係なく、「組み込み関数の互換性のない暗黙の宣言」という警告が表示されます。
ポインターの型が宣言時に変更される場合、mallocが呼び出されてキャストされるすべての行を変更する必要がある場合もあります。
が鋳造なしのmalloc関数は、好適な方法であると最も経験豊富なプログラマは、それを選択してください、あなたは問題を認識したような方、あなたを使用する必要があります。
つまり、CプログラムをC ++としてコンパイルする必要がある場合(それは別の言語ですが)、使用結果をキャストする必要がありますmalloc
。
malloc()
呼び出しから遠くに宣言されている場合に、宛先ポインターのタイプが変更された場合に、開発者がタイプサイジングの不整合を特定するのに役立つ」とはどういう意味ですか?例を挙げていただけますか?
p = malloc(sizeof(*p) * count)
イディオムはタイプの変更を自動的に取得するため、警告を受け取ったり、何かを変更したりする必要はありません。したがって、これは、キャスティングしないための最良の選択肢と比べて、実際の利点ではありません。
Cでは、void
ポインターを暗黙的に他の種類のポインターに変換できるため、キャストは必要ありません。ある人を使うことは、それを必要とする理由がいくつかあることを偶然の観察者に示唆するかもしれません。
mallocの結果をキャストしないでください。キャストすると、コードに無意味な混乱が追加されます。
mallocの結果をキャストする最も一般的な理由は、C言語がどのように機能するかがわからないためです。これは警告のサインです。特定の言語メカニズムがどのように機能するかわからない場合は、推測を取ります。調べるか、Stack Overflowで質問してください。
いくつかのコメント:
voidポインターは、明示的なキャストなしで他のポインター型との間で変換できます(C11 6.3.2.3および6.5.16.1)。
ただし、C ++では、void*
と別のポインタ型の間の暗黙的なキャストは許可されません。したがって、C ++では、キャストは正しかったでしょう。ただし、C ++でプログラミングする場合はnew
、malloc()ではなく、使用する必要があります。また、C ++コンパイラを使用してCコードをコンパイルしないでください。
同じソースコードでCとC ++の両方をサポートする必要がある場合は、コンパイラスイッチを使用して違いをマークします。互換性がないため、両方の言語標準を同じコードでまとめようとしないでください。
ヘッダーをインクルードするのを忘れたためにCコンパイラーが関数を見つけられない場合、そのことに関するコンパイラー/リンカーエラーが表示されます。したがって、それを含めるのを忘れた場合は<stdlib.h>
、大きな問題ではありません。プログラムを構築することはできません。
25年以上前の標準のバージョンに準拠している古いコンパイラでは、含める<stdlib.h>
ことを忘れると危険な動作が発生します。その古い標準では、可視プロトタイプのない関数は暗黙的に戻り値の型をint
です。mallocからの結果を明示的にキャストすると、このバグを隠すことができます。
しかし、それは実際には問題ではありません。25年前のコンピューターを使用していないのに、なぜ25年前のコンパイラーを使用するのでしょうか。
Cではvoid *
、他の(データ)ポインタからへの暗黙の変換を取得します。
によって返された値をキャストする malloc()
必要はありませんが、誰も指摘していないように見えるポイントを1つ追加したいと思います。
古代、つまりANSI Cvoid *
がポインタの一般的なタイプとしてを提供する前は、そのchar *
ような使用法のタイプです。その場合、キャストはコンパイラの警告をシャットダウンできます。
リファレンス:C FAQ
私の経験を追加するだけで、コンピューターエンジニアリングを勉強すると、Cで書いた2つか3つの教授が常にmallocをキャストすることがわかりますが、私が尋ねた(非常に高いCVとCを理解している)教授は、それは絶対に不要であると言いましたが、以前は絶対的に具体的であり、学生を絶対的に具体的であるという考え方に導くためにのみ使用されていました。基本的にキャストは、その動作方法には何も変更せず、それが言っていることを正確に実行し、メモリを割り当て、キャストはそれに影響せず、同じメモリを取得し、誤って他の何かにキャストしたとしても(コンパイラを回避してしまう)エラー)Cは同じ方法でアクセスします。
編集:キャスティングには一定のポイントがあります。配列表記を使用する場合、生成されたコードは、次の要素の先頭に到達するために進める必要のあるメモリ場所の数を知る必要があります。これは、キャストによって実現されます。これにより、doubleの場合は8バイト先に進み、intの場合は4バイト先に進むことがわかります。したがって、ポインタ表記を使用しても効果はなく、配列表記では必要になります。
p = malloc(sizeof *p * n);
は、とてもシンプルで優れています。
はをmalloc
返すため、の結果をキャストすることは必須ではなくvoid*
、a void*
は任意のデータ型を指すことができます。
voidポインターは汎用オブジェクトポインターであり、Cはvoidポインター型から他の型への暗黙的な変換をサポートしているため、明示的に型キャストする必要はありません。
ただし、暗黙的な変換をサポートしていないC ++プラットフォームで完全に互換性のある同じコードを機能させたい場合は、型キャストを行う必要があるため、すべてがユーザビリティに依存します。
malloc
C ++でのとの使用は、特別な注意(またはCでの書き換え)に値することを示す適切な警告サインです。
void *
性void *
があるため、関数ポインタを適切に格納するには不十分です。
これは、GNU Cライブラリリファレンスマニュアルの内容です。
malloc
ISO Cはvoid *
必要に応じて型を別の型のポインターに自動的に変換するため、キャストなしで任意のポインター変数に結果を格納できます。ただし、キャストは代入演算子以外のコンテキストで、またはコードを従来のCで実行したい場合に必要です。
実際、ISO C11標準(p347)は次のように述べています。
割り当てが成功した場合に返されるポインターは、基本的な配置要件を持つ任意のタイプのオブジェクトへのポインターに割り当てられるように適切に配置され、割り当てられたスペース内のそのようなオブジェクトまたはそのようなオブジェクトの配列にアクセスするために使用されます(スペースは明示的に割り当て解除されます)
返されるタイプはvoid *で、逆参照可能にするために、必要なタイプのデータポインターにキャストできます。
void*
目的のタイプにキャストできますが、自動的に変換されるため、その必要はありません。したがって、キャストは必要ありません。実際、高得点の回答で言及されている理由により望ましくありません。
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++) {
...
}
malloc()
1つではありませんが、別の問題です。
void*
関数ポインターへの割り当て、または関数ポインターからの割り当ては情報を失う可能性があるため、「無効なポインターを任意のポインターに割り当てることができます」という問題が発生します。ただしvoid*
、from malloc()
を任意のオブジェクトポインタに割り当てることは問題ではありません。
do
離れて、表題の質問から疑問に思っている、まだループを含むマクロに関連するループコメント。そのコメントを削除します。これも後で削除します。
それはプログラミング言語とコンパイラに依存します。malloc
Cで使用する場合は、自動的に型キャストされるため、型キャストする必要はありません。ただし、C ++を使用している場合はmalloc
、void*
型を返すため、キャストを入力する必要があります。
GCCとClangに慣れている人々は甘やかされて育った。それはそこに良いすべてではありません。
私は長年にわたって、私が使用することを要求された驚異的に古くなったコンパイラーにかなり恐怖を感じてきました。多くの場合、企業やマネージャーはコンパイラーの変更に非常に保守的なアプローチを採用しており、システムで新しいコンパイラー(標準への準拠とコードの最適化が優れている)が機能するかどうかをテストしません。作業している開発者にとって実際的な現実は、コーディングするときはベースをカバーする必要があることです。残念ながら、コードに適用するコンパイラーを制御できない場合は、mallocsのキャストが適切な習慣です。
また、多くの組織が独自のコーディング標準を適用し、それが定義されている場合、人々が従う方法であるべきだと提案します。明示的なガイダンスがない場合、私は標準への従順ではなく、どこでもコンパイルする可能性が最も高い傾向があります。
現在の標準では必要ないという主張は非常に有効です。しかし、その議論は現実世界の実用性を省略しています。私たちは、その日の標準によって独占的に支配された世界ではなく、私が「ローカルマネジメントの現実の分野」と呼んでいるものの実用性によってコーディングしません。そして、それは今までの時空よりも曲がりくねっています。:-)
YMMV。
私はmallocのキャストを防御的な操作と考えがちです。きれいではありませんが、完璧ではありませんが、一般的には安全です。(正直なところ、あなたはSTDLIB.H含まれていませんでしたならば、あなたがきた道のmallocのキャストよりも多くの問題!)。
型変換の醜い穴の不承認を示すために単にキャストを挿入しました。これにより、次のスニペットなどのコードを診断なしでコンパイルできます。
double d;
void *p = &d;
int *q = p;
私はそれが存在しなかった(そしてそれがC ++には存在しなかった)ことを望み、キャストします。それは私の好み、そして私のプログラミング政治を表しています。私はポインターをキャストするだけでなく、効果的に、投票用紙をキャストし、愚かな悪魔をキャストします。私が実際に 愚かさを追い出すことができないなら、少なくとも抗議のしぐさでそうすることの願いを表現させてください。
実際、malloc
を返す関数でラップ(およびフレンド)しunsigned char *
、基本的にvoid *
コードで使用しないことをお勧めします。任意のオブジェクトへの汎用ポインタが必要な場合は、char *
またはを使用unsigned char *
し、双方向にキャストします。おそらくリラックスできるリラクゼーションの1つは、キャストのような関数memset
とmemcpy
キャストのない関数を使用することです。
キャストとC ++の互換性のトピックで、CとC ++の両方としてコンパイルされるようにコードを記述した場合(この場合、以外に割り当てるときにの戻り値をキャストする必要があります)、非常に役立ちます。 C ++としてコンパイルする場合はC ++スタイルのキャストに変換するキャスト用のマクロを使用できますが、Cとしてコンパイルする場合はCキャストに縮小できます。malloc
void *
/* 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
、const
またはを削除するためだけに使用し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
。
Cでプログラミングするときは、可能な限り行うことをお勧めします。
-Wall
すべてのエラーと警告を修正します。auto
-Wall
して-std=c++11
。すべてのエラーと警告を修正します。この手順では、C ++の厳密な型チェックを利用できるため、バグの数を減らすことができます。特に、この手順では、強制的に含めるstdlib.h
か、または取得します
malloc
このスコープ内で宣言されていません
また、結果のキャストを強制します。そうしmalloc
ないと、
から
void*
への無効な変換T*
またはあなたのターゲットタイプは何ですか。
私が見つけることができるC ++ではなくCで書くことの唯一の利点は
Cに共通のサブセットを静的なポリモーフィック機能と併用すると、2番目の短所が理想的なケースではなくなることに注意してください。
C ++の厳格なルールが不便であると感じる人のために、推論された型でC ++ 11機能を使用できます
auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...
gcc -c c_code.c
)としてコンパイルし、C ++コードをC ++(eg g++ -c cpp_code.cpp
)としてコンパイルして、それらをリンクします。(たとえばgcc c_code.o cpp_code.o
、プロジェクトの依存関係に応じて、またはその逆)。いずれかの言語の優れた機能を奪う理由は何もないはずです...
p = malloc(sizeof(*p));
。これp
により、別の型名に変更した場合、最初に変更する必要はありません。提案されているキャストの「利点」p
は、型が間違っているとコンパイルエラーが発生することですが、正しく機能する場合はさらに優れています。
malloc()
。一般に、から、またはへのキャストは行いませんvoid *
。
そうしないために与えられる典型的な理由は、失敗#include <stdlib.h>
が見過ごされる可能性があることです。C99が暗黙の関数宣言を不正にしたため、これは長い間問題ではなくなりました。コンパイラが少なくともC99に準拠している場合、診断メッセージが表示されます。
しかし、不必要なポインタキャストを導入しないほうがはるかに強力な理由があります。
Cでは、ポインタキャストはほとんど常にエラーです。これは、次のルールによるものです(C11の最新のドラフトであるN1570の6.5 p7)。
オブジェクトは、次のタイプのいずれかを持つ左辺値式によってのみアクセスされる格納された値を持つ必要があります。—
オブジェクト
の有効なタイプと互換性のあるタイプ
— — オブジェクトの有効なタイプと互換性のあるタイプの修飾バージョン、—オブジェクトの有効な型に対応する符号付きまたは符号なしの型で
ある型— オブジェクトの有効な型の修飾バージョンに対応する符号付きまたは符号なしの型である型
— 1つを含む集合体または共用体型メンバー間の前述のタイプ(再帰的には、サブアグリゲートまたは含まれるユニオンのメンバーを含む)、または
—文字タイプ。
これは、厳密なエイリアスルールとも呼ばれます。したがって、次のコードは未定義の動作です。
long x = 5;
double *p = (double *)&x;
double y = *p;
そして、時には意外なことに、以下も同様です。
struct foo { int x; };
struct bar { int x; int y; };
struct bar b = { 1, 2};
struct foo *p = (struct foo *)&b;
int z = p->x;
場合によっては、ポインタをキャストする必要がありますが、厳密なエイリアシングルールが与えられているため、非常に注意する必要があります。したがって、コード内でキャストされたポインタは、その有効性を再確認する必要がある場所です。したがって、不要なポインターキャストを記述することはありません。
一言で言えば:Cには、のでどんなの発生ポインタキャストは、特別な注意が必要なコードのための赤い旗を上げる必要があり、あなたは書くべきではありません不要なポインタのキャストを。
サイドノート:
実際にへのキャストが必要な場合がありますvoid *
。たとえば、ポインタを出力したい場合は、次のようになります。
int x = 5;
printf("%p\n", (void *)&x);
キャストはprintf()
可変個の関数であるため、ここで必要です。したがって、暗黙的な変換は機能しません。
C ++では状況が異なります。ポインタ型のキャストは、派生クラスのオブジェクトを処理するときにいくぶん一般的(かつ正しい)です。したがって、C ++では、暗黙的な変換void *
は行われません。C ++には、さまざまな種類のキャストがあります。
私はキャストを好むが、手動ではない。私のお気に入りは、使用しているg_new
とg_new0
のglibからマクロ。glibを使用しない場合は、同様のマクロを追加します。これらのマクロは、型の安全性を損なうことなくコードの重複を減らします。型が間違っていると、非voidポインター間の暗黙的なキャストが発生し、警告(C ++のエラー)が発生します。g_new
and を定義するヘッダーを含めるのを忘れるとg_new0
、エラーが発生します。g_new
そして、g_new0
両方が同じ引数malloc
をとりますcalloc
。追加0
するだけで、ゼロで初期化されたメモリを取得できます。コードは、C ++コンパイラで変更せずにコンパイルできます。
キャストはC ++専用であり、Cではありません。C++コンパイラを使用している場合は、Cコンパイラに変更することをお勧めします。
voidポインターの背後にある概念は、任意のデータ型にキャストできることです。これが、mallocがvoidを返す理由です。また、自動型キャストにも注意する必要があります。したがって、ポインタをキャストすることは必須ではありませんが、実行する必要があります。コードをクリーンに保ち、デバッグに役立ちます
voidポインターは汎用ポインターであり、Cはvoidポインター型から他の型への暗黙的な変換をサポートしているため、明示的に型キャストする必要はありません。
ただし、暗黙的な変換をサポートしていないC ++プラットフォームで完全に互換性のある同じコードを機能させたい場合は、型キャストを行う必要があるため、すべてがユーザビリティに依存します。
他の述べたように、それはCではなくC ++に必要です。
キャストを含めると、Cプログラムまたは関数をC ++としてコンパイルできる場合があります。
Cではvoid *が自動的かつ安全に他のポインタ型に昇格されるため、これは不要です。
しかし、キャストした場合、stdlib.hをインクルードするのを忘れた場合、エラーを隠すことができ ます。これにより、クラッシュが発生する可能性があります(さらに悪いことに、コードの完全に異なる一部の部分まではクラッシュしません)。
stdlib.hにはmallocのプロトタイプが含まれているため、これが見つかります。mallocのプロトタイプがない場合、標準では、Cコンパイラがmallocがintを返すことを前提としています。キャストがない場合、この整数がポインターに割り当てられると警告が発行されます。ただし、キャストでは、この警告は生成されず、バグを隠します。
Cではmallocのキャストは不要ですが、C ++では必須です。
次の理由により、Cではキャストは不要です。
void *
Cの場合、他のポインタ型に自動的かつ安全に昇格されます。<stdlib.h>
。これにより、クラッシュが発生する可能性があります。malloc
呼び出されてキャストされるすべての行を変更する必要がある場合もあります。一方、キャストを行うとプログラムの移植性が向上する場合があります。つまり、Cプログラムまたは関数をC ++としてコンパイルできます。