今日私が他の人のコードを読んでいたとき、私はのようなものを見ましたvoid *func(void* i);
、これはvoid*
それぞれ関数名と変数タイプに対してここで何を意味しますか?
さらに、この種のポインターをいつ使用する必要がありますか?
malloc
とからキューを取得しcalloc
ます。manページにはさらに、「...割り当てられたメモリへのポインタが返されます。これは、組み込みデータ型に合わせて適切に配置されています。」
今日私が他の人のコードを読んでいたとき、私はのようなものを見ましたvoid *func(void* i);
、これはvoid*
それぞれ関数名と変数タイプに対してここで何を意味しますか?
さらに、この種のポインターをいつ使用する必要がありますか?
malloc
とからキューを取得しcalloc
ます。manページにはさらに、「...割り当てられたメモリへのポインタが返されます。これは、組み込みデータ型に合わせて適切に配置されています。」
回答:
へのポインタvoid
は、「一般的な」ポインタ型です。void *
明示的なキャストなしで、A を他のポインター型に変換できます。それを参照解除しvoid *
たり、それを使用してポインター演算を行ったりすることはできません。まず、完全なデータ型へのポインタに変換する必要があります。
void *
多くの場合、同じコードで異なるポインタ型を操作できるようにする必要がある場所で使用されます。一般的に引用される例の1つは、ライブラリ関数qsort
です。
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
base
は配列のアドレス、は配列nmemb
内の要素の数、size
各要素のサイズcompar
、配列の2つの要素を比較する関数へのポインタです。それはそのように呼ばれます:
int iArr[10];
double dArr[30];
long lArr[50];
...
qsort(iArr, sizeof iArr/sizeof iArr[0], sizeof iArr[0], compareInt);
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareDouble);
qsort(lArr, sizeof lArr/sizeof lArr[0], sizeof lArr[0], compareLong);
配列式はiArr
、dArr
、およびlArr
暗黙の関数呼び出しでポインタ型に配列型から変換され、それぞれは暗黙的「へのポインタから変換されたint
/ double
/ long
」へのポインタに「void
」。
比較関数は次のようになります。
int compareInt(const void *lhs, const void *rhs)
{
const int *x = lhs; // convert void * to int * by assignment
const int *y = rhs;
if (*x > *y) return 1;
if (*x == *y) return 0;
return -1;
}
受け入れることによってvoid *
、qsort
任意のタイプのアレイで動作することができます。
使用void *
することの欠点は、タイプセーフティをウィンドウの外に出し、対向するトラフィックに移動することです。間違った比較ルーチンを使用しないようにする方法はありません。
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);
compareInt
はその引数がint
sを指すことを期待していますが、実際にはdouble
sを使用しています。コンパイル時にこの問題を見つける方法はありません。あなたはちょうどmisorted配列で終わります。
void*
が関数ポインタにキャストできることは実際には保証されていません。しかし、データポインタについては、あなたが言ったことはそのままです。
void *を使用するということは、関数が特定の型である必要のないポインターを取ることができることを意味します。たとえば、ソケット関数では、
send(void * pData, int nLength)
つまり、たとえば、さまざまな方法で呼び出すことができます。
char * data = "blah";
send(data, strlen(data));
POINT p;
p.x = 1;
p.y = 2;
send(&p, sizeof(POINT));
ポインタに関するこの記事http://www.cplusplus.com/doc/tutorial/pointers/をご覧になり、次の章をお読みください。voidポインタ。
これはC言語でも機能します。
void型のポインターは、特殊な型のポインターです。C ++では、voidは型の不在を表します。したがって、voidポインターは、型のない値(つまり、長さが未確定で逆参照のプロパティも未確定)を指すポインターです。
これにより、voidポインターが整数値または浮動小数点から文字列までの任意のデータ型を指すことができます。しかし、引き換えにそれらには大きな制限があります:それらによってポイントされたデータは直接逆参照することができません(逆参照するタイプがないため、これは論理的です)。そのため、常にvoidポインターのアドレスをキャストする必要があります。逆参照する前に具象データ型を指す他のポインタ型。
voidポインターは、ジェネリックポインターと呼ばれます。サンプルのpthreadシナリオで説明したいと思います。
スレッド関数のプロトタイプは次のようになります
void *(*start_routine)(void*)
pthread API設計者は、スレッド関数の引数と戻り値を考慮しました。それらがジェネリックになっている場合、引数として送信するときにvoid *へのキャストを入力できます。同様に、戻り値はvoid *から取得できます(ただし、スレッド関数からの戻り値は使用していません)。
void *PrintHello(void *threadid)
{
long tid;
// ***Arg sent in main is retrieved ***
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0; t<NUM_THREADS; t++){
//*** t will be type cast to void* and send as argument.
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
}
pthread_exit(NULL);
なく、なぜ呼び出すのreturn 0;
ですか?
a void*
はポインターですが、それが指すものの型は指定されていません。関数にvoidポインターを渡す場合、後でその関数を使用するために、関数内で正しい型にキャストバックするために、その型が何であるかを知る必要があります。あなたはの例が表示されますpthreads
スレッド関数として使用されているあなたの例では、正確にプロトタイプとその利用機能を。その後void*
、選択した汎用データ型へのポインターとして引数を使用し、それをその型にキャストして、スレッド関数内で使用できます。voidポインターを使用するときは注意が必要ですが、その真の型のポインターに戻らないと、あらゆる種類の問題が発生する可能性があります。
つまり、このリンクを使用して、ポインターに関する詳細情報を取得できます 。http://www.cprogramming.com/tutorial/c/lesson6.html