mallocの結果をキャストしますか?
回答
いいえ; 次の理由により、結果をキャストしません。
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)
対malloc(length * width * sizeof *sieve)
二はオーバーフローするlength * width
ときwidth
とlength
比べて小さいタイプですsize_t
。
Cでは、の戻り値をキャストする必要はありませんmalloc
。によって返されるvoidへのポインタmalloc
は、自動的に正しい型に変換されます。ただし、コードをC ++コンパイラでコンパイルする場合は、キャストが必要です。コミュニティの中で好ましい代替手段は、以下を使用することです。
int *sieve = malloc(sizeof *sieve * length);
これにより、のタイプを変更した場合でも、式の右辺を変更する必要がなくなりますsieve
。
人々が指摘しているように、キャストは悪いです。特にポインターキャスト。
あなたがないので、キャスト:
- これにより、コードはCとC ++の間でより移植性が高くなり、SOの経験が示すように、非常に多くのプログラマーが、実際にC ++(またはCとローカルコンパイラ拡張)で記述しているのにCで記述していると主張しています。
- そうしないと、エラーが隠される可能性があります。いつ書き込む
type *
かとを混乱させるSOの例をすべて注意してくださいtype **
。 #include
適切なヘッダーファイルに失敗したことに気付かないようにするという考えは、ツリーのフォレストを見逃します。これは、「プロトタイプが表示されないことについてコンパイラに文句を言うように依頼しなかったという事実を心配しないでください。厄介なstdlib.hは覚えておくべき本当に重要なことです!」と言うのと同じです。- それは余分な認知クロスチェックを強制します。それはあなたがその変数の生のサイズのために行っている算術のすぐ隣に(主張されている)望ましいタイプを置きます。
malloc()
キャストがあるとバグがはるかに早くキャッチされることを示すSO調査を行うことができると思います。アサーションと同様に、意図を明らかにするアノテーションはバグを減らします。 - マシンがチェックできる方法で自分自身を繰り返すことは、多くの場合素晴らしいアイデアです。実際、それがアサーションであり、このキャストの使用はアサーションです。チューリングが何年も前にアイデアを思いついたので、アサーションはまだコードを正しくするために私たちが持っている最も一般的なテクニックです。
他の人が述べたように、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 ++のためにコンパイルされます。
ウィキペディアから:
鋳造の利点
キャストを含めると、Cプログラムまたは関数をC ++としてコンパイルできる場合があります。
キャストにより、元々char *を返していた1989年以前のバージョンのmallocが可能になります。
キャストは、特にポインターがmalloc()呼び出しから遠く離れて宣言されている場合に、宛先ポインターの型が変更された場合に開発者が型サイズの不整合を識別するのに役立ちます(ただし、最新のコンパイラーと静的アナライザーはキャストを必要とせずにそのような動作について警告できます)。
キャスティングのデメリット
ANSI C標準では、キャストは冗長です。
キャストを追加すると、mallocのプロトタイプが見つかったヘッダーstdlib.hを含めることができなくなる可能性があります。mallocのプロトタイプがない場合、標準では、Cコンパイラがmallocがintを返すと想定する必要があります。キャストがない場合、この整数がポインターに割り当てられると警告が発行されます。ただし、キャストでは、この警告は生成されず、バグが隠されます。特定のアーキテクチャおよびデータモデル(longおよびpointersが64ビットでintが32ビットである64ビットシステムのLP64など)では、暗黙的に宣言されたmallocが32を返すため、このエラーは実際には未定義の動作を引き起こす可能性があります。実際に定義された関数は64ビット値を返しますが、ビット値。呼び出し規約とメモリレイアウトによっては、スタックが破壊される可能性があります。この問題は、宣言されていない関数が使用されたという警告を一律に生成するため、最近のコンパイラでは見過ごされがちです。そのため、警告は引き続き表示されます。たとえば、GCCのデフォルトの動作では、キャストが存在するかどうかに関係なく、「組み込み関数の互換性のない暗黙の宣言」という警告が表示されます。
ポインタのタイプが宣言時に変更された場合、mallocが呼び出されてキャストされるすべての行を変更する必要がある場合もあります。
が鋳造なしのmalloc関数は、好適な方法であると最も経験豊富なプログラマがそれを選択、あなたは問題を認識したような方、あなたを使用する必要があります。
つまり、CプログラムをC ++としてコンパイルする必要がある場合(別の言語ですが)、使用結果をキャストする必要がありますmalloc
。
Cでは、void
ポインターを他の種類のポインターに暗黙的に変換できるため、キャストは必要ありません。使用することは、それが必要とされる理由があることをカジュアルな観察者に示唆するかもしれません、それは誤解を招くかもしれません。
の結果をキャストしないでください。キャストするmalloc
と、コードが無意味に乱雑になるためです。
人々が結果をキャストする最も一般的な理由malloc
は、C言語がどのように機能するかについて確信が持てないためです。これは警告サインです:あなたは、特定の言語機構作品は、その後、方法がわからない場合はありません推測を取ります。それを調べるか、StackOverflowで質問してください。
いくつかのコメント:
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バイト先に進むことがわかります。したがって、ポインタ表記を使用しても効果はありません。配列表記では必要になります。
malloc
、はを返すため、の結果をキャストする必要はありません。またvoid*
、avoid*
は任意のデータ型を指すことができます。
これは、GNUCライブラリリファレンスマニュアルの内容です。
malloc
ISO Cはvoid *
必要に応じて型を別の型のポインタに自動的に変換するため、キャストなしでの結果を任意のポインタ変数に格納できます。ただし、代入演算子以外のコンテキストで、またはコードを従来のCで実行する場合は、キャストが必要です。
そして実際、ISO C11標準(p347)はそう言っています:
割り当てが成功した場合に返されるポインタは、基本的な配置要件を持つ任意のタイプのオブジェクトへのポインタに割り当てられ、割り当てられたスペース内のそのようなオブジェクトまたはそのようなオブジェクトの配列にアクセスするために使用できるように適切に配置されます(スペースは明示的に割り当て解除されます)
voidポインターはジェネリックオブジェクトポインターであり、Cはvoidポインター型から他の型への暗黙的な変換をサポートしているため、明示的に型キャストする必要はありません。
ただし、暗黙の変換をサポートしないC ++プラットフォームで同じコードを完全に互換性のあるものにしたい場合は、型キャストを行う必要があるため、すべてが使いやすさに依存します。
返される型はvoid *であり、参照解除できるようにするために、目的の型のデータポインタにキャストできます。
プログラミング言語とコンパイラによって異なります。malloc
Cで使用する場合は、自動的に型キャストされるため、型キャストする必要はありません。ただし、C ++を使用している場合はmalloc
、void*
型を返すため、castと入力する必要があります。
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++) {
...
}
GCCとClangに慣れている人々は甘やかされています。そこにあるのはそれほど良いことではありません。
私は何年にもわたって、私が使用することを要求されてきた驚くほど古くなったコンパイラーにかなり恐怖を感じてきました。多くの場合、企業やマネージャーはコンパイラーの変更に非常に保守的なアプローチを採用しており、新しいコンパイラー(より優れた標準コンプライアンスとコード最適化を備えた)がシステムで機能するかどうかをテストしません。作業中の開発者にとっての実際的な現実は、コーディングするときにベースをカバーする必要があるということです。残念ながら、コードに適用するコンパイラを制御できない場合は、mallocをキャストすることをお勧めします。
また、多くの組織が独自のコーディング標準を適用し、それが定義されている場合はそれが人々が従う方法であるべきだと提案します。明確なガイダンスがない場合、私は標準への順守よりも、どこでもコンパイルする可能性が最も高い傾向があります。
現在の基準では必要ないという議論は非常に有効です。しかし、その議論は現実世界の実用性を省略しています。私たちは、その日の標準だけで支配されている世界でコーディングするのではなく、私が「ローカル管理の現実分野」と呼んでいるものの実用性によってコーディングします。そして、それは時空よりも曲がったりねじれたりしています。:-)
YMMV。
私はmallocのキャストを防御的な操作と考える傾向があります。きれいではなく、完璧ではありませんが、一般的に安全です。(正直なところ、あなたはSTDLIB.H含まれていませんでしたならば、あなたがきた道のmallocのキャストよりも多くの問題!)。
いいえ、の結果をキャストしませんmalloc()
。
通常、にキャストしたり、からキャストしたりvoid *
することはありません。
そうしないことの典型的な理由は、失敗#include <stdlib.h>
が見過ごされる可能性があることです。C99が暗黙の関数宣言を違法にしたため、これは長い間問題ではなくなりました。したがって、コンパイラが少なくともC99に準拠している場合は、診断メッセージが表示されます。
しかし、不要なポインタキャストを導入しない理由ははるかに強力です。
Cでは、ポインタのキャストはほとんどの場合エラーです。これは、次のルールによるものです(N1570の§6.5p7、C11の最新ドラフト)。
オブジェクトの格納値には、次のいずれかの型を持つ左辺値式によってのみアクセスする必要があります。—
オブジェクト
の有効型と互換性のある型
— —オブジェクトの有効型と互換性のある型の修飾バージョン—オブジェクトの有効な型に対応する符号付きまたは符号なしの型で
ある型—オブジェクトの有効な型の修飾バージョンに対応する符号付きまたは符号なしの型である型—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;
ポインタをキャストする必要がある場合もありますが、厳密なエイリアシングルールを考えると、非常に注意する必要があります。したがって、コード内でポインターがキャストされた場合は、その有効性を再確認する必要があります。したがって、不要なポインタキャストを書き込むことはありません。
tl; dr
一言で言えば:Cには、のでどんなの発生ポインタキャストは、特別な注意が必要なコードのための赤い旗を上げる必要があり、あなたは書くべきではありません不要なポインタのキャストを。
サイドノート:
ポインタを出力する場合など、実際にキャストが必要な場合があり
void *
ます。int x = 5; printf("%p\n", (void *)&x);
printf()
は可変個引数関数であるため、ここではキャストが必要です。したがって、陰関数変換は機能しません。C ++では、状況が異なります。派生クラスのオブジェクトを処理する場合、ポインタ型のキャストはやや一般的(かつ正しい)です。したがって、それはC ++、およびからの変換は、その意味が
void *
あるではない暗黙。C ++には、さまざまな種類のキャストがあります。
型システムの醜い穴の不承認を示すためにキャストを挿入しました。これにより、悪い変換を引き起こすためにキャストが使用されていなくても、次のスニペットなどのコードを診断なしでコンパイルできます。
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
。
私はキャストをすることを好みますが、手動ではありません。私のお気に入りは、使用しているg_new
とg_new0
のglibからマクロ。glibを使用しない場合は、同様のマクロを追加します。これらのマクロは、型の安全性を損なうことなくコードの重複を減らします。型を間違えると、void以外のポインター間で暗黙のキャストが発生し、警告(C ++ではエラー)が発生します。g_new
とを定義するヘッダーを含めるのを忘れるとg_new0
、エラーが発生します。g_new
とg_new0
は異なり、どちらも同じ引数malloc
を取りますcalloc
。追加0
するだけで、初期化されていないメモリを取得できます。コードは、変更なしでC ++コンパイラでコンパイルできます。
可能な場合はいつでも、Cでプログラミングするときに行う最善のこと:
- すべての警告をオンにしてCコンパイラでプログラムをコンパイルし、
-Wall
すべてのエラーと警告を修正します - として宣言された変数がないことを確認してください
auto
- その後でC ++コンパイラを使ってコンパイル
-Wall
して-std=c++11
。すべてのエラーと警告を修正します。 - ここで、Cコンパイラを使用して再度コンパイルします。これで、プログラムは警告なしにコンパイルされ、バグが少なくなります。
この手順により、C ++の厳密な型チェックを利用できるため、バグの数を減らすことができます。特に、この手順では、含めるstdlib.h
必要があります。そうしないと、次のようになります。
malloc
このスコープ内で宣言されていません
また、結果をキャストするように強制します。そうしmalloc
ないと、
から
void*
への無効な変換T*
またはあなたのターゲットタイプが何であれ。
私が見つけることができるC ++の代わりにCで書くことからの唯一の利点は
- Cには明確に指定されたABIがあります
- C ++は、より多くのコードを生成する可能性があります[例外、RTTI、テンプレート、ランタイムポリモーフィズム]
静的多型機能と一緒にCに共通のサブセットを使用すると、理想的な場合には2番目の短所がなくなることに注意してください。
C ++の厳密なルールが不便だと思う人のために、推定型でC ++ 11機能を使用できます。
auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...
キャストはCではなくC ++専用です。C++コンパイラを使用している場合は、Cコンパイラに変更することをお勧めします。
mallocのキャストはCでは不要ですが、C ++では必須です。
次の理由により、Cではキャストは不要です。
void *
Cの場合、は自動的かつ安全に他のポインタタイプに昇格します。- を含めるのを忘れた場合、エラーを非表示にすることができます
<stdlib.h>
。これにより、クラッシュが発生する可能性があります。 - ポインタと整数のサイズが異なる場合は、キャストによって警告を非表示にしているため、返されたアドレスのビットが失われる可能性があります。
- ポインタのタイプが宣言時に変更された場合、
malloc
呼び出されてキャストされるすべての行を変更する必要がある場合もあります。
一方、キャストはプログラムの移植性を高める可能性があります。つまり、Cプログラムまたは関数をC ++としてコンパイルできます。
voidポインターの背後にある概念は、mallocがvoidを返す理由である任意のデータ型にキャストできるということです。また、自動型キャストに注意する必要があります。したがって、ポインタをキャストする必要はありますが、キャストする必要はありません。コードをクリーンに保つのに役立ち、デバッグに役立ちます
voidポインターはジェネリックポインターであり、Cはvoidポインター型から他の型への暗黙的な変換をサポートしているため、明示的に型キャストする必要はありません。
ただし、暗黙の変換をサポートしないC ++プラットフォームで同じコードを完全に互換性のあるものにしたい場合は、型キャストを行う必要があるため、すべてが使いやすさに依存します。
他に述べたように、Cには必要ありませんが、C ++には必要です。
キャストを含めると、Cプログラムまたは関数をC ++としてコンパイルできる場合があります。
Cでは、void *が自動的かつ安全に他のポインタ型にプロモートされるため、これは不要です。
ただし、キャストした場合、stdlib.hを含めるのを忘れると、エラーが非表示になる可能性があり ます。これによりクラッシュが発生する可能性があります(さらに悪いことに、コードのまったく異なる部分で後でクラッシュが発生することはありません)。
stdlib.hにmallocのプロトタイプが含まれているため、が見つかりました。mallocのプロトタイプがない場合、標準では、Cコンパイラがmallocがintを返すと想定する必要があります。キャストがない場合、この整数がポインターに割り当てられると警告が発行されます。ただし、キャストでは、この警告は生成されず、バグが隠されます。
この質問は意見に基づく虐待の対象です。
時々私はそのようなコメントに気づきます:
または
OPがキャストを使用する質問について。コメント自体には、この質問へのハイパーリンクが含まれています。
それはである任意の可能な方法は不適切と間違ったとしても。それが本当に自分自身のコーディングスタイルの問題である場合、正しいことも悪いこともありません。
なんでこんなことが起こっているの?
これは2つの理由に基づいています。
この質問は確かに意見に基づいています。技術的には、質問は数年前に意見に基づいて閉じられるべきでした。「ドI」または「DoがないI」または同等の「万一I」や「べきではない私が」という質問、あなただけの答えは自分の意見の姿勢なしに集中することはできません。質問を閉じる理由の1つは、ここによく示されているように、「意見に基づく回答につながる可能性がある」ためです。
多くの回答(@unwindの最も明白で受け入れられている回答を含む)は、完全にまたはほぼ完全に意見に基づいており(キャストまたは繰り返しを行うとコードに追加される不思議な「混乱」が悪い)、表示されますキャストを省略する明確で焦点を絞った傾向。彼らは一方のキャストの冗長性について議論しますが、さらに悪いことに、プログラミング自体のバグ/失敗によって引き起こされたバグを解決することを主張します-
#include <stdlib.h>
使用したい場合はそうではありませんmalloc()
。
私の個人的な意見を少なくして、議論されたいくつかの点の本当の見方をもたらしたいと思います。特に注意する必要があるいくつかのポイント:
自分の意見に陥るような非常に影響を受けやすい質問には、中立的な賛否両論の答えが必要です。短所や長所だけではありません。
長所と短所の良い概要は、この回答に記載されています:
https://stackoverflow.com/a/33047365/12139179
(私は個人的にこれをその理由のためにこれまでのところ最良の答えだと考えています。)
キャストの省略を理由としてせいぜい遭遇する1つの理由は、キャストがバグを隠す可能性があることです。
この質問に示されているように、誰かが暗黙の宣言
malloc()
を使用して、int
(暗黙の関数はC99以降標準からなくなった)とを返す場合sizeof(int) != sizeof(int*)
このコードが64ビットアーキテクチャでセグメンテーション違反を起こすのに、32ビットでは正常に機能するのはなぜですか?
キャストはバグを隠します。
これは真実ですが、キャストの省略はさらに大きなバグの前向きな解決策にすぎないため、ストーリーの半分しか示していません-を
stdlib.h
使用する場合は含まれませんmalloc()
。これは決して深刻な問題にはなりません。
C99以上(推奨され、必須である必要があります)に準拠したコンパイラーを使用し、
コードで
stdlib.h
使用malloc()
したいときに、を含めるのを忘れていないわけではありません。これは、それ自体が大きなバグです。
キャストはC ++で義務付けられているため、CコードのC ++準拠について議論する人もいます。
まず第一に、一般的に言うと、CコードをC ++コンパイラでコンパイルすることは良い習慣ではありません。
CとC ++は、実際には、セマンティクスが異なる2つの完全に異なる言語です。
ただし、CコードをC ++に準拠させる必要がある場合、またはその逆の場合は、キャストの代わりにコンパイラスイッチを使用してください。
キャストは冗長または有害でさえあると宣言される傾向があるので、これらの質問に焦点を当てたいと思います。キャストが有用または必要でさえある理由を説明します。
- コード、それぞれ割り当てられたポインターのタイプ(およびそれに伴うキャストのタイプ)が変更された場合、キャストは有益ではない可能性がありますが、これはほとんどの場合ありそうにありません。次に、すべてのキャストも維持/変更する必要があります。コード内でメモリ管理関数を数千回呼び出すと、これは実際に要約され、保守効率が低下する可能性があります。
概要:
事実は、割り当てられたポインタが基本的な配置要件のオブジェクト(すべてのオブジェクトのほとんどを含む)を指している場合、キャストはC標準(ANSI-C(C89 / C90)以降)に従って冗長であるということです。
この場合、ポインタは自動的に整列されるため、キャストを行う必要はありません。
「aligned_alloc、calloc、malloc、realloc関数への連続呼び出しによって割り当てられるストレージの順序と連続性は指定されていません。割り当てが成功した場合に返されるポインターは、適切に整列されているため、任意のタイプのオブジェクトへのポインターに割り当てることができます。基本的な配置要件であり、割り当てられたスペース内のそのようなオブジェクトまたはそのようなオブジェクトの配列にアクセスするために使用されます(スペースが明示的に割り当て解除されるまで)。」
出典:C18、§7.22.3/ 1
「基本的な配置とは、以下の有効な配置です
_Alignof (max_align_t)
。基本的な配置は、すべての保存期間のオブジェクトの実装によってサポートされるものとします。次のタイプの配置要件は、基本的な配置でなければなりません。—すべてのアトミック、修飾、または非修飾の基本型。
—すべてのアトミック、修飾、または非修飾の列挙型。
—すべてのアトミック、修飾、または非修飾のポインター型。
—要素タイプに基本的な配置要件があるすべての配列タイプ; 57)
—第7項で完全なオブジェクトタイプとして指定されているすべてのタイプ。
—すべての構造体または共用体タイプ。そのすべての要素には基本的な配置要件のある型があり、どの要素にも基本的な配置ではない配置を指定する配置指定子はありません。
- 6.2.1で指定されているように、後の宣言は前の宣言を隠す可能性があります。」
出典:C18、§6.2.8/ 2
ただし、拡張アライメント要件の実装定義オブジェクトにメモリを割り当てる場合は、キャストが必要になります。
拡張された位置合わせはより大きなアラインメントによって表されます
_Alignof (max_align_t)
。拡張アライメントがサポートされているかどうか、およびそれらがサポートされているストレージ期間は実装によって定義されます。拡張アライメント要件のあるタイプは、オーバーアライメントタイプです58)。ソース。C18、§6.2.8/ 3
他のすべては、特定のユースケースと自分の意見の問題です。
自分の教育方法に注意してください。
これまでに行ったすべての回答(および失敗を示す可能性のあるコメント)を最初に注意深く読んmalloc()
でから、特定のケースで結果をキャストしない場合は、独自の意見を作成することをお勧めします。
ご注意ください:
その質問に対する正しい答えと間違った答えはありません。それはスタイルの問題であり、あなた自身があなたがどちらの方法を選ぶかを決定します(もちろんあなたが教育や仕事によって強制されていない場合)。そのことに注意し、だまされないようにしてください。
最後の注意:私は最近、この質問を意見ベースとして閉じることに投票しました。これは実際に何年もの間必要とされています。クローズ/リニューアルの権限をお持ちの方もぜひご参加ください。
私にとっては、ここでテイクホームおよび結論は、鋳造ということであるmalloc
Cには全く必要ありませんが、あなたはしかしキャスト場合、それが影響を与える文句を言わないmalloc
とmalloc
、まだあなたにあなたの要求恵まれメモリ空間を割り当てます。もう1つの持ち帰りは、人々がキャストを行う理由または理由の1つです。これは、CまたはC ++で同じプログラムをコンパイルできるようにするためです。
他の理由もあるかもしれませんが、他の理由は、ほぼ確実に、遅かれ早かれ深刻な問題にあなたを着陸させるでしょう。
Cでキャストすることはできますが、必須ではありません。そのコードがC ++としてコンパイルされている場合は、キャストする必要があります。