このコードは、-Wall を指定した GCC でコンパイルおよび実行されます。
#include <stdio.h>
struct event_cb;
typedef void (*event_cb_t)(const struct event_cb *evt, void *user_data);
struct event_cb
{
event_cb_t cb;
void *data;
};
static struct event_cb saved = { 0, 0 };
void event_cb_register(event_cb_t cb, void *user_data)
{
saved.cb = cb;
saved.data = user_data;
}
static void my_event_cb(const struct event_cb *evt, void *data)
{
printf("in %s\n", __func__);
printf("data1: %s\n", (const char *)data);
printf("data2: %s\n", (const char *)evt->data);
}
int main(void)
{
char my_custom_data[40] = "Hello!";
event_cb_register(my_event_cb, my_custom_data);
saved.cb(&saved, saved.data);
return 0;
}
おそらく、コールバック関数が構造体 event_cb 全体を取得するかどうかを確認する必要があります。通常は、データを渡すだけです。これは、実証されているように、そうでなければ、同じ情報の 2 つのソース (およびへのポインターの予備のコピー) があるためです。あなたがいる機能)。これに対して実行できるクリーンアップはたくさんありますが、うまくいきます。
コメントの質問:これはコールバックの良い例ですか?
簡潔に言うと、そうではありません。ただし、ここには十分なインフラストラクチャがないためです。
ある意味では、qsort()
に渡される比較関数と考えることができます。 または bsearch()
コールバックとして機能します。これは、ジェネリック関数がそれ自体では実行できないことを実行する、ジェネリック関数に渡される関数へのポインターです。
コールバックのもう 1 つの例は、シグナル ハンドラ関数です。イベント (シグナル) が発生したときに関数を呼び出すようにシステムに指示します。システムが関数を呼び出す必要があるときに、どの関数を呼び出す必要があるかをシステムが認識できるように、事前にメカニズムをセットアップします。
サンプル コードは、より精巧なメカニズム (コンテキストを伴うコールバック) を提供しようとしています。 C++ では、これはおそらくファンクターになります。
私が扱っているコードの中には、特定のコンテキストで使用する場合、メモリ管理に関して非常に面倒な要件があるものがあります。したがって、テストのために malloc()
を使用します などですが、本番環境では、メモリ アロケーターを特殊なアロケーターに設定する必要があります。次に、パッケージに関数呼び出しを提供して、うるさいコードがデフォルトのメモリ アロケーターを独自のサロゲート バージョンでオーバーライドできるようにします。サロゲートが正常に機能する場合、コードは以前と同じように動作します。これらはコールバックの形式です - 繰り返しますが、ユーザー コンテキスト データの方法で多く (または何も) を必要としない形式です。
ウィンドウ システムには、登録されたイベント ハンドラー (コールバック) があり、イベントが発生したときに GUI メイン イベント ループが呼び出します。これらは通常、GUI システムによって提供されるイベント固有の情報だけでなく、ユーザー コンテキストも必要とします。
「コールバックを登録する」とは、基礎となるシステムに対して、呼び出す正確な関数と (オプションで) どのパラメーターを指定するか、また場合によってはそのコールバックを呼び出すイベントの特定のクラスを指定することです。
「イベント ディスパッチャー」は、O/S (または GUI など) からイベントを受信し、登録されたコールバックのリストを調べて、そのイベントに関心のあるものを確認することにより、実際にコールバックを呼び出します。
コンパイラの出力がなければ難しいですが、いくつか問題があります。
int event_cb_register(event_ct_t cb, void *user_data);
int event_cb_register(event_cb_t cb, void *user_data);
my_custom_data
ここで使用されている場合、変数は存在しません;
event_cb_register(my_event_cb, &my_custom_data);
このポインターは初期化されません。
struct event_cb *callback;
そして;
callback->cb(event, callback->data);
タイプ ('event') の名前を関数に渡すことはできません。そのタイプのインスタンスを渡す必要があります。