C言語のvoid型ポインタ変数について

このQ&Aのポイント
  • C言語のvoid型ポインタ変数について質問があります。
  • 組み込み系の開発を行っているのですが、現在使用しているシステムで提供されているAPIの引数の多くはvoid型ポインタとなっています。
  • なぜvoid型はよろしくないのか疑問に思っています。
回答を見る
  • ベストアンサー

C言語のvoid型ポインタ変数について。

C言語のvoid型ポインタ変数について。 C言語のvoid型ポインタ変数について質問があります。 組み込み系の開発を行っているのですが、現在使用しているシステムで、 提供されている "API" を介してアプリケーション部のソフト作成を行っています。 この "API" ですが、引数の多くはvoid型ポインタとなっています。 ある人がこの引数がvoid型となっているのを見て、 『なんでvoid型なんや??、C言語でアセンブラと違うんやから、void型なんかにしない方が良い』 とおっしゃいました。 この意味がよくわからなかったのですが、なぜ void型はよろしくないんでしょうか? -- 僕が思うに、APIなんやから引数を void型ポインタ にすることでどんな型にも対応できる 汎用的であると感じ、逆にこの方が良いのではと感じたのですが。。 -API例---- int _exApiKannsuu( char in_data, void* out_data ) "in_data" をもとに "out_data" を取得する。 どーやらこの "out_data" が void型 であるのががよくないらしい・・

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

  • ベストアンサー
  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

同じ関数で 複数の型のデータを扱うのでなければ特定の型のポインタにしたほうが良いでしょう このAPI宣言だけみた使用者は 何型のポインタを渡せば良いのかわかりません char*で良いのか int*が必要なのかはたまた何かの構造体のポインタを要求しているのか ・・・

その他の回答 (4)

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.5

>int _exApiKannsuu( char in_data, void* out_data ) 他の方も指摘されていますが、この関数がin_dataを元に 何を行ってout_dataに何を返すのかがわかりません。 それにout_dataに何を指定すればいいのか、どのくらいのサイズが 必要なのかもわかりません。どんな型にも対応できるということは、 どんな型を渡せばよいか分からないということでもあります。 逆にこの関数を作った人も、out_dataがどこまで書き込めるのか、 などが判りづらくなり、特定の決まったもの処理して返すならば、 out_dataのサイズを渡すかそのサイズ分の領域がわかるような引数を 取るべきだと思います。 どんなものにも例外はあると思いますが、今回であれば 該当の関数が与えられる引数の型に依存しない処理を行うのであれば void*型でも良いと思います。(その場合はその領域のサイズを指定させるなどが良く行われると思いますが)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

> 僕が思うに、APIなんやから引数を void型ポインタ にすることでどんな型にも対応できる > 汎用的であると感じ、逆にこの方が良いのではと感じたのですが。。 その論法からすれば、関数原型を止めてしまうか、第2引数以降を可変個引数にした方が汎用性が高まるはずです。 しかし、実際にはそんなことはありません。 void*をint*や構造体型*のようにしても、(C++ではないので)コンパイル時にエラーを検出できるわけではありませんが、警告ぐらいは出ることを期待できます。 ただし、(memcpyのように)具体的な型情報が必要ない場合には、void*の方がよいでしょう。 それに_exApiKannsuuという関数名がよくありません。この名前を見ても、何をする関数なのかさっぱり分かりません。当然、各引数に何を渡せばよいのかも想像がつきません。また、下線から始まる外部識別子は予約済み識別子であり、こんな関数名では動作が未定義になります。さらに、Kannsuuというのは「関数」の意味のローマ字表記だと思いますがスペルが間違っています。 こうした状況を考えると設計も実装も非常に怪しく、すべてに対して疑ってかかりたくなる気持ちも十分理解できます。

回答No.3

「void型ポインタ にすることでどんな型にも対応できる」ので、 うっかり間違ってもコンパイル時にエラーとなってくれません。 /* 文字列の長さを返す関数があったとしよう */ int stringLength(void* str); /* strは文字列であるべし! */ int n; int length = stringLength(&n); /* エラーにしてくれない */

  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.2

あなたの意見の通りだと思います。 本来はある人の意見のように、全ての型の引数を用意し、同じ関数名で関数定義すべきなのかもしれません。しかし、その組合せが組合せの爆発を起こすと、そうも言っていられないでしょう。なので、あるシリーズの関数群の引数は、違う型の可能性のあるものはvoidポインタで統一する、というのはありだと思います。

関連するQ&A

  • C言語のvoid型ポインタを使いたいのですが…

    C言語のvoid型ポインタを使いたいのですが… 関数の引数として、void型ポインタを使おうと思ったのですが、内部でどのように処理すればいいのかわかりません キャストすれば問題なく使えるとのことですが、どの型でキャストするのかをどのように判断するのかがわかりません 具体的には、画像処理で画像の構造体をいくつか作ったのですが、それぞれの構造体ごとに関数を書くと関数が多くなるので、void型ポインタでまとめてつくろうとしています どのように型の判断を行えばいいのかを教えてください

  • C言語のコールバック

    Java/C#/PHPといった言語はすでに使えるのですが、現在C言語およびWin32 APIを勉強中です。 C言語の関数にはJavaなどのインスタンスメソッドのthisにあたる引数が渡されませんが、Win32 APIのウィンドウプロシージャに代表されるコールバック関数において不都合があります。Javaの場合は、 interface Callback{ void onCallback(); } といったインターフェイスが定義されているものとして、 hoge(new Callback(){ int data = 10; public void onCallback(){ System.out.println(data); } }); のようなコードで引数以外のデータも参照できますが、C言語ではこのように引数で渡せないデータを参照するにはどうしたらよいでしょうか。グローバル変数として参照するのは、Javaのstaticなフィールドと同様に拡張性を損なうので避けたいと思います。

  • C言語での関数の引数の受け渡しについて

    C言語での関数の引数の受け渡しについて教えてもらいたいのです。 char *p=Goo;  というポインタpがmain関数で定義され、このポインタpをある関数 void func(・・・) に渡すことは出来ますか? つまりポインタを実引数として扱うことはできるのかという事ですが・・・ int p=10; とかだったら、 void func(int test) の関数には、main関数で func(p) で仮引数testにわたせると思うんですが・・・ もし出来るようでしたら、関数の渡し方と定義の記述を教えてください。 どうか宜しくお願いします。

  • 関数の引数を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型へのポインタ

    というのがC言語にありますよね? このvoid型へのポインタというのは、 どのようにイメージすればいいのでしょうか? 例えばchar型へのポインタなら、 指している領域は 1バイトの領域ですよね? ではvoid型は? また malloc関数を 使って char *p; p=(char *)malloc(1000); とするとでchar型にキャストしているから、 1個1バイト分の領域が1000個用意して、 先頭アドレスをpに格納するのですよね? では、 int *q; q=(int *)malloc(1000); としたら、用意されるのは、int型にキャストしているから 1個2バイト分の領域が500個用意されるのでしょうか? お願いします。

  • C言語の変数について

    C言語の変数について教えていただきたいです。 C言語で下記のような設定をした場合、変数A、Bに設定する値にはバイト数制限 はないのでしょうか? バイト数制限がなくなる場合、なぜそうなるのかを教えていただきたいです。 よろしくお願いします。 #include <stdio.h> void test( char **B); int main( int argc, char *argv[] ) { char *A = NULL; char *B = NULL; A = argv[1]; test( B ); return 0; } void test( char **B ) { strcpy(B, "ABCD"); return 0; }

  • C言語の配列とポインタについて

    C言語の配列とポインタについてわからないことがあります。 以下のソース例は、10個の値の平均値を求めるプログラムです。 コメントを挟んだ部分が疑問点です。 【ソース例】 #include <stdio.h> int getaverage(int *data); int main(void) { int average,array[10] = {15,78,98,15,98,85,17,35,42,15}; average = getaverage(array); printf("%d\n",average); return 0; } int getaverage(int *data) { int i,average = 0; for (i = 0;i < 10;i++) { average += data[i]; /*ポインタ変数なのに? */ } return average / 10; } 【実行例】 49 このdata[i]はポインタ変数であり、 配列arrayの i 番目の要素であるarray[i]の"アドレス" が代入されているはずだと思うのですが、 なぜ通常の整数変数であるaverageと数値計算が出来、正しい結果が出たのでしょうか? あたかもdata[i]には、 array[i]の"アドレス"ではなく、 array[i]の"メモリの中身"が代入されているようです。 どういうことでしょうか? 回答よろしくお願いします。

  • char型のポインタ配列に変数の値の代入できる?

    c言語でchar型のポインタ配列に変数の値を代入できるのでしょうか? 例えば int A[10]={1,2,3,4,5,6,7,8,9,10}; char *C[10]; のCに配列Aの中のデータを文字列として入れたいのです。 C[0]="A[0]"としてもA[0]という文字列が代入されてしまうだけなので… よろしくお願いします。

  • void型ポインタについて

    -------------------------------- #include<stdio.h> void uni_disp(void *p,int typ); int main() { int idt=123456; double ddt=56.789; char ss[]="abcdef"; uni_disp(&idt,'I'); uni_disp(&ddt,'D'); uni_disp(ss,'S'); uni_disp("STRING",'S'); return 0; } void uni_disp(void *p,int typ) { if(typ=='I'){ printf("%d\n",*(int *)p); } else if(typ=='D'){ printf("%f\n",*(double *)p); } else if(typ=='S'){ printf("%s\n",(char *)p); } } ----------------------------------- 以上のプログラム等で、void型ポインタをint型ポインタ、double型ポインタとみなす場合の、「*(int *)p」や「*(double *)p」の表記がどういう仕組みになっているか分かりません。 「*(int)p」などはエラーが出るのですが、やはり表記の意味を理解していないため何故か分かりません。 「*(int *)p」などの表記を分解して教えていただけると嬉しいです。

  • C言語計算プログラム

    Cの計算プログラム 下のプログラムを (1)上位桁の不要な0を表示しない (2)3つの数を計算できるようにする (3)0が入力されるまでは入力を受け付けて加算を繰り返す プログラムに改造する方法を教えてください。 #include <stdio.h> #define MAXDIGIT 70 void reset(char*,int); void input(char*,int); void add(char*,char*,char*,int); void add_digit(char ,char ,char ,char* ,char* ); void display(char* ,char* ,char* ,int ); void lineprint(char ,char* ,int ); void linedraw(char ,int ); int main(void) { char a[MAXDIGIT],b[MAXDIGIT],c[MAXDIGIT]; reset(a,MAXDIGIT); reset(b,MAXDIGIT); reset(c,MAXDIGIT); input(a,MAXDIGIT); input(b,MAXDIGIT); add(a,b,c,MAXDIGIT); display(a,b,c,MAXDIGIT); return 0;} void reset(char* buf,int maxdigit) { int i; for(i=0;i<maxdigit;i++) buf[i]=0; return;} void input(char* buf,int maxdigit) { char str[MAXDIGIT]; int i,j; printf("input data:"); scanf("%s",str); i=0; while(str[i]!='\0') i++; j=0; while(i>0){ buf[j]=str[i-1]-'0'; j++; i--; } return;} void add(char* a,char* b,char* c,int maxdigit) { int i; char carry_in,carry_out; i=0; carry_in=0; while(i<maxdigit) { add_digit(a[i],b[i],carry_in,&c[i],&carry_out); carry_in=carry_out; i++;} return;} void add_digit(char a,char b,char carry_in,char* c,char* carry_out) { *c=(a+b+carry_in)%10; *carry_out=(a+b+carry_in)/10; return;} void display(char* a,char* b,char* c,int maxdigit) { lineprint(' ',a,maxdigit); lineprint('+',b,maxdigit); linedraw('-',maxdigit+1); lineprint(' ',c,maxdigit); return;} void lineprint(char c,char* line,int maxdigit) { int i,maxdigitlimit; maxdigitlimit=maxdigit-1; printf("%c",c); for(i=maxdigitlimit;i>=0;i--){ printf("%1d",line[i]); } printf("\n"); return;} void linedraw(char c,int length) { int i; for(i=0;i<length;i++) printf("%c",c); printf("\n"); return;}

専門家に質問してみよう