教科書の 1 つを調べていると、C 関数の次のコード行が表示されます。
node_t* func(node_t* n, int f(node_t *))
これは正確にはどういう意味ですか?そこに引数としての関数があります。そのポイントは何ですか?宣言されている限り、ファイル内の任意の関数を呼び出すことができるべきではありませんか? また、アセンブル的には、参照されているのは int f() のメモリ位置ですか?
ありがとうございました。
教科書の 1 つを調べていると、C 関数の次のコード行が表示されます。
node_t* func(node_t* n, int f(node_t *))
これは正確にはどういう意味ですか?そこに引数としての関数があります。そのポイントは何ですか?宣言されている限り、ファイル内の任意の関数を呼び出すことができるべきではありませんか? また、アセンブル的には、参照されているのは int f() のメモリ位置ですか?
ありがとうございました。
node_t* func(node_t* n, int f(node_t *))
n は node_t へのポインターであり、f は node_t ポインターを受け取り、int を返す関数へのポインターです。関数 func は、node_t へのポインターを返します。
とにかく、頭に浮かぶこれの最も一般的な用途は、汎用アルゴリズムです。
「宣言されている限り、ファイル内の関数を呼び出すことができるはずではありませんか?」
関数がコンパイル単位で宣言されていて、リンカーがリンク時にそれを見つけることができる限り、それは真実です。ただし、関数ポインターは、使用する関数を実行時に決定できるようにする場合 (または、汎用関数が必要な場合はコンパイル時に使用する場合) に使用されます。
具体的な例として、qsortを考えてみましょう:
void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );
これを考慮してください:
typedef struct Student { int id; char* name; }
Student students[10];
//populate students
int sortByName(void* a, void* b)
{
Student* sa = a;
Student* sb = b;
return strcmp(a->name, b->name);
}
int sortById(void* a, void* b)
{
Student* sa = a;
Student* sb = b;
return a->id - b->id;
}
//sort by name:
qsort(students, 10, sizeof(Student), sortByName);
//sort by id:
qsort(students, 10, sizeof(Student), sortById);
重要な部分は、並べ替えコードを変更する必要がなかったことです。ソートの実装は事実上汎用的です。これは、さまざまなデータ型で動作する 1 つのアルゴリズムであり、この場合、この汎用性は関数ポインターによって促進されます。
コールバックや、何かを関数にマップするマップに基づく分岐など、関数ポインターの他の用途 (かなりの数) もあります。