コンパイラの警告をもっと真剣に受け止める必要があります。
C では、コンパイラが無効なプログラムを拒否する必要はありません。ルール違反の「診断」が必要なだけです。診断は、致命的なエラー メッセージまたは警告のいずれかです。
残念ながら、互換性のないポインター型の割り当てに対してコンパイラが警告を発行するのはよくあることです。
void main()
これは間違っています; である必要がありますint main(void)
。あなたのコンパイラはそれを回避できるかもしれませんし、目に見える問題を引き起こさないかもしれませんが、正しく書かないことには意味がありません。(それほど単純ではありませんが、これで十分です。)
int *p;
float q;
q = 6.6;
それで大丈夫です。
p = &q;
p
タイプint*
です。&q
タイプfloat*
です。(キャストなしで)一方を他方に割り当てることは、制約違反です。それを見る最も簡単な方法は、それが単に違法であるということです。
この割り当てを本当に実行したい場合は、キャストを使用できます。
p = (int*)&q; /* legal, but ugly */
しかし、そうする正当な理由はめったにありません。 p
へのポインタint
です。他の何かを指すようにする非常に正当な理由がない限り、int
オブジェクトを指す必要があります。状況によっては、変換自体が未定義の動作をすることがあります。
printf("*p = %f \n q = %f, p = %p, &q = %p \n",*p,q,p,&q);
%f
形式にはdouble
引数が必要です (引数はこのコンテキストでfloat
昇格されるため、問題ありません)。しかし、タイプです。間違った型の引数で呼び出すと、プログラムの動作が未定義になります。double
float
*p
int
printf
%p
void*
ポインタ型だけでなく、 type の引数が必要です。ポインター値を出力したい場合は、次のようにキャストする必要がありますvoid*
。
printf("&q = %p\n", (void*)&q);
キャストなしで動作する可能性がありますが、動作は未定義です。
プログラムをコンパイルするときに警告が表示された場合は、わざわざ実行する必要はありません。最初に警告を修正します。
あなたのタイトルの質問に関しては、タイプのポインターint*
とfloat*
は異なるタイプです。はオブジェクトint*
を指す必要があります。int
aはオブジェクトfloat*
を指す必要がありfloat
ます。コンパイラはそれらを混在させることができますが、その結果は実装定義または未定義のいずれかになります。C 言語、特に多くの C コンパイラでは、あまり意味のない多くのことを回避できます。
それらが異なるタイプである理由は、それらの使用におけるエラーを防止する、または少なくとも検出するためです。type のオブジェクトを宣言する場合は、それがオブジェクトint*
を指すことを意図していると言っていint
ます (null ポインターでない場合)。オブジェクトのアドレスをfloat
オブジェクトに保存するint*
ことは、ほぼ間違いなく間違いです。型安全性を強制することで、そのような間違いをできるだけ早く (重要なクライアントのデモ中にプログラムがクラッシュしたときではなく、コンパイラが警告を出力したときに) 検出できます。
int*
とfloat*
が同じサイズで、同じ内部表現を持っている可能性があります (ただし、保証はされません) 。しかし、オブジェクトの意味は、int*
「仮想アドレスを含む 32 (または 64) ビットの集まり」ではなく、「int
オブジェクトを指すもの」です。