• ベストアンサー

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

  • 「void ( *signal(int sig, void (*func)(int)) ) (int)」の (int)

    signal関数の書式についてですが、   void ( *signal(int sig, void (*func)(int)) ) (int); 最後に付く(int)は一体何でしょうか? このような関数の書式ははじめて見ました。 UNIX系の何かでしょうか。 回答よろしくお願いします。

  • 関数の引数を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++ではありません。

  • (void *)と&の違い

    #include<stdio.h> void * func(void *p){ printf("□■□func開始□■□\n"); printf("pのアドレス = %p\n",p); printf("p = %d\n",(int)p); (int)p += 100; printf("p = %d\n",(int)p); printf("□■□func開始□■□\n"); return NULL; } int main(void){ int number = 30; printf("numberのアドレス = %p\n",&number); func((void *)number);★1 return 0; } -------------------------------------------------------------- #include<stdio.h> void * func(int *p){ printf("□■□func開始□■□\n"); printf("pのアドレス = %p\n",p); printf("p = %d\n",*p); *p += 100; printf("p = %d\n",*p); printf("□■□func開始□■□\n"); return NULL; } int main(void){ int number = 30; printf("numberのアドレス = %p\n",&number); func(&number);★2 return 0; } 上記の2つは同じ結果になるのですが★1と★2のそれぞれの違いがわかりません。どなたかご教授をお願いします。

  • int main(void)

    C言語の問題集をやっているのですが、 本にはmain関数の最初にint main(void)のような書き方が してあります。 学校ではmain() と習ったのですが、本には上のようにかいてあります。 どのように違うのでしょうか? というかmain関数のところに引数が入っている意味がわかりません。 どういうことがというと(void)ってなんですか? またint mainというのはint型の関数だと思うのですが、 なかではdouble型とかも使えます。 お願いします。

  • int main()、void main()、void main(void)、int main(void)

    今日、大学でC言語の講義の時間、先生が、 #include <stdio.h> void main(void){ } と宣言してプログラムを書くと教えていました。 main関数には、 main() void main() void main( void ) int main() int main( void ) と、人によりいくつかの描き方があったりします。 どれが本当は正しいのでしょうか? void mainはすべきではないとなんかの本で読んだのですが・・。

  • 教えてポインタ

    例えば、以下のようなソース。 関数の中で、引数のポインタに値を入れてmainに戻す。 とても簡単なものです。 void func(int *N) {  *N=0; } main {  int  *N=1;  func(N);  printf("%d",*N) } 疑問は、ここからです。 (1)void func(int  *N) (2)void func(int*  N) (3)void func(int*  &N) 上記は、何が違いますか? なお、当方のVS2010で同じソースを作ると、 (1)の場合、エラーになります。(func関数の*N=0のところでダウン) (2)だと、OKになります。 (3)は、なに?

  • プログラムがわかりません

    C言語の本を読んでいるんですが、詰まってしまいました。プログラム自体は単純なのですが #include<stdio.h> void hello(void) { fprintf(stderr,"hello!\n"); } void func(void) { void *buf[10]; static int i; for(i=0;i<10;i++) { buf[i] = hello; } } int main(void) { int buf[100]; func(); return 0; } のスタックオーバーフローのプログラムです。 1. 要素100のint型配列を宣言 2. 関数funcの呼び出し 3. void *buf[10]; まずここでがわかりません。なぜポインタが   でてきたのか?またbufの要素数は100では? 4. buf[i] = hello; のループ    これもわかりません。配列に関数を代入しているのでしょうか?     5.  fprintf(stderr,"hello!\n"); これもまたわかりません。    fprintfの最初の引数は出力先ですが、なぜ標準エラー出力なの   でしょうか? 時間のあるかた解説お願いします。

  • signal関数の使い方

    標準関数のsignal()関数についてですが void (*signal(int sig, void (*func)(int)))(int); 関数の形式からしてよくわかりません。 僕のイメージでは関数のポインタというと void (*func)(int,int) という感じですが上の場合 void (*func(int,int))(int) /*引数は仮にint型*/ という形式になってますよね。末尾の(int)は引数のはずですがどこの引数になっているのかよくわかりません。 しかも関数の使用例などをみると signal(SIGINT, func); という形で使っており末尾の(int)がどこにいったのかさっぱりわかりません。 よろしくお願いします。

  • extern指定子の使い方

    こんにちは。 現在WindowsVistaでCプログラミングを行っています。 独習Cという本に沿って勉強しているのですが、extern指定子の使い方の所でつまずきました。 まず、サンプルプログラムを参照し、以下のような2つのファイルを作成しました。 (必要なヘッダファイルは全てインクルードしています。) ●main.c ____________________________________________________________ extern int random; void func(void); void main(void) { int i; for(i=1; i<=10; i++){ func(); printf("発生した乱数 : %d\n", random); } } ____________________________________________________________ ●func.c ____________________________________________________________ int random; void func(void) { long ltime; long utime; /*まず、time()関数とsrand()関数を使って乱数列の初期値を 毎回変更できるようにする*/ ltime=time(NULL); utime=(unsigned int)ltime/2; srand(utime); //乱数を発生させてrandomに代入する random=rand(); } ____________________________________________________________ この2つのファイルをコンパイルし、実行した所同じ整数が10個表示されました。 異なる整数を10個表示したいのですが、どうすればよいかが分からず困っています。 何か分かる方がいらっしゃれば、アドバイスをお願い致します。

  • 暗黙のキャストを自動検出

    C++には暗黙のキャストがあります。 例えば、下記の例のようにint型(4バイト)の引数を取る関数short型(2バイト)の引数を与えて呼び出した場合。 ------------------- void func(int i) { //... } int main() { short s = 1; func(s); // short->intに暗黙のキャスト } このコードは正常にコンパイルすることができ、かついかなる警告レベルでも警告は表示されません。(VS環境) データ欠損やオーバーフローの可能性はなく、安全なキャストであることが保障されているからです。(short型の取り得る値の全てがint型の散り得る範囲に収まる) このような「暗黙のキャスト」を行っている箇所を自動的に検出する方法はあるでしょうか? 暗黙ではない(危険な)キャストはIDEにより警告が出ることは分かっています。 Visual Studiioの機能、または外部ツールを使用する方法でも構いません。あるいは、この目的のためにダミーを作成するようなやり方でも構いません。 funcを使用している箇所は膨大ですがfuncの数は限られていますので、この目的のために仮の関数を定義してコンパイルしてみることは可能です。 一応考えてみた方法は、下記のような検出用の関数を追加することです。 ------ 暗黙のキャスト検出用オーバーロード関数 ------- void func(short i) // 必要に応じてchar型や byte型をとるオーバーロード関数も作成 { // この関数が呼ばれたら暗黙のキャスト! cout << "関数" << __FUNCTION__ << "で暗黙のキャスト(int->short)が行われました。">>"\n"; // 続きの処理を継続するため、本当の関数を呼んでおく func((int)i); // ここは明示的にキャストしないと自分自身を呼んでしまう } ただこの方法ではコンパイル時に検出できず、実際に全ての関数呼び出しが実行されるようにプログラムを動かす必要があります。 また、検出用関数も暗黙のキャストのパターン数分用意する必要があります。目視で全ソースチェックするのとあまりコストが変わらないような気がします。 主に関数の引数として渡されるデータ型が仮引数にコピーされる際にキャストされる場面を検出したいのですが、関数の戻り値を別の変数に代入している場面も検出できればなお良いです。 なぜこのようなことが必要かと思われるかもしれませんが、暗黙のキャストそのものが問題ではなく、そうした箇所に別の問題が潜んでいる可能性があり、それを調べたいのです。 こうした場面がソース中に大量にあると想定されるため、漏れなく機械的に検出する方法があればと思い質問しました。

このQ&Aのポイント
  • 最近、同じデータを縫っていても以前よりサテン縫いで自動糸切りをした箇所がほつれやすくなっている。
  • 縫い上がった生地の裏側を見ると、止めがあまい?糸の終点がゆるくなっていることがわかる。
  • 考えられる原因として、太すぎる線をサテン縫いで縫っている可能性がある。対策としては、タタミ縫いにする、裏側からほつれ止め液を多めに塗るなどが挙げられる。
回答を見る