現在C言語を勉強しているのですが、void **型の引数を受け取る場合の動作が分からず困っています。
関数がvoid *型の引数を受け取る場合、呼び出し側ではキャストせずに任意の型のポインタを渡すことができますが、void **型の引数を渡す場合には明示的に(void**)とキャストしないとコンパイルでエラーが発生します。
なぜvoid *型を渡す場合はキャストの必要がないのに、void **型ではキャストが必要になるのでしょうか?
いろいろ調べてみたのですが、void*型や通常の変数の**型について説明しているサイトは見つかりましたが、void**型について説明しているサイトが見つからなかっため質問させて頂きます。
開発環境等の情報は以下の通りです。
よろしくお願いします。
・環境
WindowsXP SP3、VC6.0
・コンパイルエラーの内容
error C2664: 'test' : 1 番目の引数を 'char ** ' から 'void ** ' に変換できません。 (新しい機能 ; ヘルプを参照)
指示された型は関連がありません; 変換には reinterpret_cast、 C スタイル キャストまたは関数スタイルのキャストが必要です。
・テスト用のソース
void**型を引数として受け取る関数について
Re: void**型を引数として受け取る関数について
Cではなく、C++でビルドしているからだと思います。
Cではエラーは出ないはずです。
追記:
なお、合っているかは自信が無いのですが、
私の調べた限りでは、C++でvoid** への暗黙的な変換ができない理由は
単に「そういう仕様」であるというだけのようです。
理論上はCと同じようにvoid** への暗黙的な変換は可能ですが、
C++の場合はvoid* 以外への暗黙的な変換は許可せずに、エラーを出す仕様なっているようです。
参考:
http://oshiete.goo.ne.jp/qa/4028893.html
Cではエラーは出ないはずです。
追記:
なお、合っているかは自信が無いのですが、
私の調べた限りでは、C++でvoid** への暗黙的な変換ができない理由は
単に「そういう仕様」であるというだけのようです。
理論上はCと同じようにvoid** への暗黙的な変換は可能ですが、
C++の場合はvoid* 以外への暗黙的な変換は許可せずに、エラーを出す仕様なっているようです。
参考:
http://oshiete.goo.ne.jp/qa/4028893.html
Re: void**型を引数として受け取る関数について
エラーになるのはC++だからなのですが,そもそも任意の型Tへのポインタ型へのポインタ型T **をvoid **に変換することはundefined behaviorの可能性を持つため,すべきではないです。H-AMA さんが書きました:関数がvoid *型の引数を受け取る場合、呼び出し側ではキャストせずに任意の型のポインタを渡すことができますが、void **型の引数を渡す場合には明示的に(void**)とキャストしないとコンパイルでエラーが発生します。
なぜvoid *型を渡す場合はキャストの必要がないのに、void **型ではキャストが必要になるのでしょうか?
いろいろ調べてみたのですが、void*型や通常の変数の**型について説明しているサイトは見つかりましたが、void**型について説明しているサイトが見つからなかっため質問させて頂きます。
# ISO/IEC 9899:1999 6.3.2.3 Pointers / Paragraph 7。
void *は特殊なポインタです。
任意の(オブジェクト/不完全/関数)型Tへのポインタ型であるT *と相互に変換できる型となっています。
# 上記 Paragaraph 1
これができるのは,コンパイラが「片方がvoid *型であることを知っており,もう片方の型も知っている」からです。
void *とT *の表現やアラインが異なれば,コンパイラが勝手に調整します。
これに対して,void **というのはvoid *へのポインタでしかありません。
void *という型のオブジェクトへのポインタを保持する型なので,特殊性は一切ありません。
コンパイラが勝手に調整をしてくれるようなこともありません。
ref) C FAQ 4.9 http://www.kouno.jp/home/c_faq/c4.html#9
Re: void**型を引数として受け取る関数について
なるほど、void *型のポインタを保持するというのがポイントなんですね。
void **型について理解できた気がします。
参考URLも見ましたが、C FAQは仕様について詳細に説明されていてとても参考になります。
じっくり読んで勉強しようと思います。
それにしても、「調べた範囲では見つからなかったので…」と書いていたのに、ずばり回答が記載されているサイトがあったんですね。
一体何を調べてたんだろう…。
h2so5さん、YuOさん、回答どうもありがとうございました!
void **型について理解できた気がします。
参考URLも見ましたが、C FAQは仕様について詳細に説明されていてとても参考になります。
じっくり読んで勉強しようと思います。
それにしても、「調べた範囲では見つからなかったので…」と書いていたのに、ずばり回答が記載されているサイトがあったんですね。
一体何を調べてたんだろう…。
h2so5さん、YuOさん、回答どうもありがとうございました!