ポインター関数にポインターを渡す方法については少し混乱しています。問題なく理解している関数(ExecBlock)へのポインターを取る関数があります。しかし、逆参照されたポインター(正確には何なのかわかりません)を受け取り、渡された関数に引数がある場合は引数を取る関数(ExecBlock2)の別のプロトタイプが与えられます。誰かが優先順位と、ポインター関数の逆参照が何をするかを正確に説明できたら。関数自体を渡すだけではありませんか?この場合、(void *)は何をしますか?
int ExecBlock (void (*f) (void), int isSet)
{
return ExecBlock2( HOW TO PASS HERE? , NULL, isSet);
}
int ExecBlock2(void *(*f)(void *), void *arg, int isSet)
{
... more code
}
_void (*f) (void)
_
voidを返す引数なしの関数へのポインタを意味します。
_void *(*f)(void *)
_
voidポインターを取り、voidポインターを返す関数へのポインターを意味します。
型が異なるため、コンパイラはキャストせずに一方を他方に渡すことを許可しません。 (ここで、キャストは実際には正しい答えではないことに注意してください。@ detlyが指摘しているように、結果は未定義の動作になります。)
関数へのポインターの逆参照に関しては、関数ポインターを呼び出すために明示的に「*」を置く必要はありません。たとえば、次のようにするだけで関数ポインタfを呼び出すことができます。
_f();
_
関数f
があり、_takes_a_function
_という関数に渡したいとします。 _takes_a_function
_はおそらく次のような型を持ちます
_void takes_a_function(void (*f)(void *data), void *data);
_
_takes_a_function
_への2つの引数、関数ポインター、およびデータへのvoidポインターがあることに注意してください。また、関数f
は引数としてvoidポインターを受け取ることに注意してください。考えは、データを_takes_a_function
_に渡すことができ、f
に渡すことです。たとえば、_takes_a_function
_は次のように定義できます。
_void takes_a_function(void (*f)(void *), void *data) {
f(data);
}
_
それでは、_takes_a_function
_に渡す関数を書きましょう。この関数は、渡されたintを出力するだけです。
_void prints_an_int(void *data) {
// The idiom for converting a void pointer to another kind
// of pointer. NO NEED TO CAST. Note this behavior is only
// defined if the pointer data really does point to an int.
int *i = data;
printf("%d", *i);
}
int i = 0;
takes_a_function(prints_an_int, &i);
_
この例に関するいくつかの重要なポイント:
prints_an_int
_は、_takes_a_function
_が期待する関数ポインターと同じ型を持っています。キャストする必要はありません。&
_演算子を使用する必要はありません。これが、_prints_an_int
_を_takes_a_function
_に直接渡すことができる理由です。しかし、takes_a_function(&prints_an_int, &i)
と言うこともできますが、それは同じです。void*
_は、基本的に「不明な型へのポインター」を意味します。実際にそれを行うには、タイプ_void*
_の変数を、期待するタイプの別のポインター変数に割り当てる必要があります。これは、実際に正しいポインター型を渡した場合にのみ機能することが保証されています!この例では、データが実際にintを指しているため、data
を_int*
_に割り当てることができます。単なる整数よりも多くのデータが必要な場合、一般的なパターンは、必要なすべてのフィールドを含む独自の構造体型を作成し、代わりに渡すことです。たとえば、あなたは機能を持っています
void * abc(void *)
{
//...
}
int ExecBlock (void (*f) (void), int isSet)
{
return ExecBlock2( abc , NULL, isSet); //use name of the function which have void * as parameter type list and return type void *
}
int ExecBlock2(void *(*f)(void *), void *arg, int isSet)
{
... more code
}
function-pointers を参照してください