アプリ版:「スタンプのみでお礼する」機能のリリースについて

最近見かけた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++ではありません。

A 回答 (3件)

>私の知っている知識では、


>void* と 任意の型のポインタは キャストなしに相互に代入可能です。

そのとおりです。
キャストの必要はありません。
あってもなくてもかまいません。


>関数の引数でも、キャストは要らないものだと思っていました。
>そうすると、引数を void* でキャストするのは無意味だと思うのですが、・・・
>違うのでしょうか。処理系によるとか。

明示的に”void*にしているよ!”ということを示したい場合などに私はよく書きます。
まぁ、書いても書かなくても一緒ってことですけど。

>逆に、関数の引数の型がchar*などで、渡すものが void* のときはどうなのでしょうか。

こちらに関しては、Cではエラーは出ませんが、C++ではエラーになります。
    • good
    • 2
この回答へのお礼

>明示的に”void*にしているよ!”ということを示したい場合などに私はよく書きます。
>まぁ、書いても書かなくても一緒ってことですけど。

>>逆に、関数の引数の型がchar*などで、渡すものが void* のときはどうなのでしょうか。
>Cではエラーは出ません

ありがとうございます。わかりました。十分です。

お礼日時:2002/07/17 22:45

> ここの意味を確認させていただきたいのですけど。



関数のポインタについてのコードを含めて、補足に書かれた通りです。

規格上保証されていないとあっても、私も、期待した通りに動作しない処理系には
出会ったことがありません。

仮想メモリ上で、heap や stack に置かれるものを指すポインタと、コードが
置かれる領域を指すポインタに互換性があるわけではない、という意味だと解釈
しています。
    • good
    • 0
この回答へのお礼

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

お礼日時:2002/07/18 22:15

> void* と 任意の型のポインタは キャストなしに相互に代入可能です。



ほとんど正しい知識です。「ほとんど」と書いたのは、関数のポインタだけは
ANSI の規格上、保証されていないからです。

すくなくとも、質問に

> また、C言語の質問であって、C++ではありません。

とあるのが、ある程度正しい理解をしているのだ、と想像させます。


> 逆に、関数の引数の型がchar*などで、渡すものが void* のときはどうなのでしょうか。

「渡すものが void* である」というのが、意味がありません(*)。規格上は、変換を
保証されてはいますが、それは、void* が指している内容についてまで保証して
いるわけではありません。質問にあるプログラムが、以下のようになっていても
意味がない、ということは分かるでしょう。

void byte_order(char* vp)
  ...

int a = 0x12345678;
void* p = &a;
byte_order(p);

  (*) 特別な場合、例えば、組み込み系のプログラムで直接物理アドレスを
    指すようなケースはありますが、あくまでも、特別な場合です。

この回答への補足

「任意の型のポインタ」と書いたときに思い浮かべていたのは、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;
}

補足日時:2002/07/18 00:22
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!