void**型を引数として受け取る関数について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
H-AMA

void**型を引数として受け取る関数について

#1

投稿記事 by H-AMA » 9年前

現在C言語を勉強しているのですが、void **型の引数を受け取る場合の動作が分からず困っています。

関数がvoid *型の引数を受け取る場合、呼び出し側ではキャストせずに任意の型のポインタを渡すことができますが、void **型の引数を渡す場合には明示的に(void**)とキャストしないとコンパイルでエラーが発生します。
なぜvoid *型を渡す場合はキャストの必要がないのに、void **型ではキャストが必要になるのでしょうか?
いろいろ調べてみたのですが、void*型や通常の変数の**型について説明しているサイトは見つかりましたが、void**型について説明しているサイトが見つからなかっため質問させて頂きます。

開発環境等の情報は以下の通りです。
よろしくお願いします。

・環境
WindowsXP SP3、VC6.0

・コンパイルエラーの内容
error C2664: 'test' : 1 番目の引数を 'char ** ' から 'void ** ' に変換できません。 (新しい機能 ; ヘルプを参照)
指示された型は関連がありません; 変換には reinterpret_cast、 C スタイル キャストまたは関数スタイルのキャストが必要です。

・テスト用のソース

コード:

void test(void** a)
{
   ...
}

int main()
{
   char* p;

   test(&p);            // エラー
   test((void**)&p);    // OK

   return 0;
}

アバター
h2so5
副管理人
記事: 2212
登録日時: 9年前
住所: 東京
連絡を取る:

Re: void**型を引数として受け取る関数について

#2

投稿記事 by h2so5 » 9年前

Cではなく、C++でビルドしているからだと思います。
Cではエラーは出ないはずです。

追記:
なお、合っているかは自信が無いのですが、
私の調べた限りでは、C++でvoid** への暗黙的な変換ができない理由は
単に「そういう仕様」であるというだけのようです。

理論上はCと同じようにvoid** への暗黙的な変換は可能ですが、
C++の場合はvoid* 以外への暗黙的な変換は許可せずに、エラーを出す仕様なっているようです。

参考:
http://oshiete.goo.ne.jp/qa/4028893.html

YuO
記事: 941
登録日時: 9年前
住所: 東京都世田谷区

Re: void**型を引数として受け取る関数について

#3

投稿記事 by YuO » 9年前

H-AMA さんが書きました:関数がvoid *型の引数を受け取る場合、呼び出し側ではキャストせずに任意の型のポインタを渡すことができますが、void **型の引数を渡す場合には明示的に(void**)とキャストしないとコンパイルでエラーが発生します。
なぜvoid *型を渡す場合はキャストの必要がないのに、void **型ではキャストが必要になるのでしょうか?
いろいろ調べてみたのですが、void*型や通常の変数の**型について説明しているサイトは見つかりましたが、void**型について説明しているサイトが見つからなかっため質問させて頂きます。
エラーになるのはC++だからなのですが,そもそも任意の型Tへのポインタ型へのポインタ型T **をvoid **に変換することはundefined behaviorの可能性を持つため,すべきではないです。
# 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

H-AMA

Re: void**型を引数として受け取る関数について

#4

投稿記事 by H-AMA » 9年前

なるほど、void *型のポインタを保持するというのがポイントなんですね。
void **型について理解できた気がします。

参考URLも見ましたが、C FAQは仕様について詳細に説明されていてとても参考になります。
じっくり読んで勉強しようと思います。

それにしても、「調べた範囲では見つからなかったので…」と書いていたのに、ずばり回答が記載されているサイトがあったんですね。
一体何を調べてたんだろう…。

h2so5さん、YuOさん、回答どうもありがとうございました!

閉鎖

“C言語何でも質問掲示板” へ戻る