• ベストアンサー

関数の引数をvoid*でキャストする

最近見かけたCのプログラムで、関数の引数の型は void* なのですが、その関数を使うときに 引数をvoid*でキャストしていました。 例えば、 func ( (void*) p ); こういうことです。 私の知っている知識では、 void* と 任意の型のポインタは キャストなしに相互に代入可能です。 関数の引数でも、キャストは要らないものだと思っていました。 そうすると、引数を void* でキャストするのは無意味だと思うのですが、・・・ 違うのでしょうか。処理系によるとか。 逆に、関数の引数の型がchar*などで、渡すものが void* のときはどうなのでしょうか。 下のプログラムは、関数byte_orderの引数の型はvoid*ですが、int型へのポインタ( &a )を設定しています。私の環境では、コンパイルエラーも警告もないし、動作も正常です。 #include <stdio.h> #include <string.h> void byte_order(void *vp) { char char_array[4]; strncpy(char_array, vp, 4); printf("出力します:%x %x %x %x\n", char_array[0], char_array[1], char_array[2], char_array[3]); } int main(void) { int a = 0x12345678; byte_order(&a); return 0; } このプログラムは単なる一例であって、質問はバイトオーダに関するものではありません。 また、C言語の質問であって、C++ではありません。

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

  • ベストアンサー
  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.1

>私の知っている知識では、 >void* と 任意の型のポインタは キャストなしに相互に代入可能です。 そのとおりです。 キャストの必要はありません。 あってもなくてもかまいません。 >関数の引数でも、キャストは要らないものだと思っていました。 >そうすると、引数を void* でキャストするのは無意味だと思うのですが、・・・ >違うのでしょうか。処理系によるとか。 明示的に”void*にしているよ!”ということを示したい場合などに私はよく書きます。 まぁ、書いても書かなくても一緒ってことですけど。 >逆に、関数の引数の型がchar*などで、渡すものが void* のときはどうなのでしょうか。 こちらに関しては、Cではエラーは出ませんが、C++ではエラーになります。

noname#2045
質問者

お礼

>明示的に”void*にしているよ!”ということを示したい場合などに私はよく書きます。 >まぁ、書いても書かなくても一緒ってことですけど。 >>逆に、関数の引数の型がchar*などで、渡すものが void* のときはどうなのでしょうか。 >Cではエラーは出ません ありがとうございます。わかりました。十分です。

その他の回答 (2)

  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.3

> ここの意味を確認させていただきたいのですけど。 関数のポインタについてのコードを含めて、補足に書かれた通りです。 規格上保証されていないとあっても、私も、期待した通りに動作しない処理系には 出会ったことがありません。 仮想メモリ上で、heap や stack に置かれるものを指すポインタと、コードが 置かれる領域を指すポインタに互換性があるわけではない、という意味だと解釈 しています。

noname#2045
質問者

お礼

よかった、書いたとおりだったようで。

  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.2

> void* と 任意の型のポインタは キャストなしに相互に代入可能です。 ほとんど正しい知識です。「ほとんど」と書いたのは、関数のポインタだけは ANSI の規格上、保証されていないからです。 すくなくとも、質問に > また、C言語の質問であって、C++ではありません。 とあるのが、ある程度正しい理解をしているのだ、と想像させます。 > 逆に、関数の引数の型がchar*などで、渡すものが void* のときはどうなのでしょうか。 「渡すものが void* である」というのが、意味がありません(*)。規格上は、変換を 保証されてはいますが、それは、void* が指している内容についてまで保証して いるわけではありません。質問にあるプログラムが、以下のようになっていても 意味がない、ということは分かるでしょう。 void byte_order(char* vp)   ... int a = 0x12345678; void* p = &a; byte_order(p);   (*) 特別な場合、例えば、組み込み系のプログラムで直接物理アドレスを     指すようなケースはありますが、あくまでも、特別な場合です。

noname#2045
質問者

補足

「任意の型のポインタ」と書いたときに思い浮かべていたのは、char* や int* ですが、「任意の」という表現は、確かに関数のポインタも含めますね。 >> void* と 任意の型のポインタは キャストなしに相互に代入可能です。 >ほとんど正しい知識です。「ほとんど」と書いたのは、関数のポインタだけは >ANSI の規格上、保証されていないからです。 ここの意味を確認させていただきたいのですけど。 「void*型の変数に、関数へのポインタを代入したり、 関数へのポインタに、void*型の変数を代入する」 ということについてですね。 例えば、次のプログラム(実用的な意味に乏しいですが…。とりあえず私の環境ではコンパイル・リンク時にエラーも警告もなく、動作も正常) ANSIの規格上保証されないということは、エラーになる処理系があっても問題はないことになるわけですね。 #include <stdio.h> #include <string.h> int main( void ) { void *vp; size_t ( * func_P ) (const char *); vp = strlen ; /* void*型の変数に、関数へのポインタを代入する。*/ printf( " vpは%p\n" , vp ) ; printf( " strlenは%p\n" , strlen ) ; func_P = vp ; /* 関数へのポインタに、void*型の変数を代入する。 */ printf(" \"abcdefg\" の長さは%d\n" , func_P("abcdefg") ); return 0; }

関連するQ&A

専門家に質問してみよう