• ベストアンサー

void*にキャストするのがナンセンス?

以下のような関数シグネチャがあったとして、 void func(void* v); この関数をコールするときに、以下のようにするのは 笑える行為だと書かれた本がありました。 int i = 0; func((void*)i); これは何がまずいのでしょうか? 本にはその説明がありませんでした。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

すでに回答があるとおりですが。 void * という型は、「あらゆるポインタ型から、安全に型変換できる」ということになっています。 また、void func(void *v); のような宣言をプロトタイプ宣言といいます。 プロトタイプ宣言の役割は、ひとつには、引数と返値の型が実際に呼ばれるときの型と合致しているかどうかをチェックするためのものですが、もうひとつ、「暗黙の型変換」を可能にするためでもあります。 たとえば、 void func(char c); int i; func(i); と書けば、プロトタイプ宣言から、実査に要求されている引数は、char であることがわかるので、暗黙のうちに、 func((char)i); という型変換が行われます。 これと同じように、 void func(void *v); というプロトタイプ宣言があれば、 int i = 0; func(&i); は、暗黙のうちに、func((void *)&i); という型変換が行われます。。 なおかつ、前述のように、void * は、あらゆるポインタ型からの型変換が可能なので、明示的に (void *) という型キャストをつける必要はないということです。 こちらは、他のポインタ型から、void * への変換です。 なお、void * から、他のポインタ型への変換は、Cでは「暗黙のうちに安全に」行われましたが、C++では、明示的にキャストが必要です。 こちらは、void * から他のポインタ型への変換です。

rotofrot
質問者

お礼

詳細な解説ありがとうございます。 とても理解が深まりました。

その他の回答 (3)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

言語規約としては「整数からポインタへの変換 (またはその逆) はできるけどその結果は処理系定義」です. UNIX だと「ビットパターンを保存して変換」になることが多いと思うので, 「UNIX である限り」は問題ないんじゃないですかね>#3. ちなみに質問に挙げられている「整数からポインタへの変換」には原則としてキャストが必須.

rotofrot
質問者

お礼

よくわかりました。 ありがとうございます。

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.3

どの本に書いてあったのでしょうか。 互換性のためにあまり良い方法ではないことは確かですが、void*に整数値を渡すことはコールバックなどで実際に使われますよね。 # 一例 http://homepage3.nifty.com/owl_h0h0/unix/job/UNIX/kernel/pthread.html 言語規約からすればこのようなコードは意図通りに動作する保証はないのでしょうけど。

rotofrot
質問者

お礼

サンプルを提示していただいてありがとうございます。 読んでみます。

  • x415f484f
  • ベストアンサー率71% (57/80)
回答No.1

まず確認ですが > int i = 0; > func((void*)i); という記述は誤植か投稿時の間違いであって int i = 0; func((void *)&i); ではないのでしょうか? # もし「func((void*)i)」で合っているのであれば、ポインタではなく変数そのままを渡すのも # 「笑える行為」だと言いたいのかも知れません。 > これは何がまずいのでしょうか? つまり「func((void *)&i)」の場合は「func(&i)」とすれば良いという意味かと思われます。 void * は汎用ポインタという呼ばれ方もしていて、どの型のポインタでも引数に渡しても良いはずなので 別の型のポインタを渡す時に「敢えて void にキャストするのがナンセンスである」という意味ではないか と思われます。 # と、一般人の私が書いておけば、専門家の方が詳しく説明して下さるかと……

rotofrot
質問者

お礼

ご指摘のとおりです。 &iの間違いでした。 ありがとうございます。 すっきりしました。

関連するQ&A