我已经开始审查回调。我在 SO 上找到了这个链接: What is a "callback" in C and how are they implemented?它有一个很好的回调示例,与我们在工作中使用的非常相似。然而,我试图让它工作,但我有很多错误。
#include <stdio.h>
/* Is the actual function pointer? */
typedef void (*event_cb_t)(const struct event *evt, void *user_data);
struct event_cb
{
event_cb_t cb;
void *data;
};
int event_cb_register(event_ct_t cb, void *user_data);
static void my_event_cb(const struct event *evt, void *data)
{
/* do some stuff */
}
int main(void)
{
event_cb_register(my_event_cb, &my_custom_data);
struct event_cb *callback;
callback->cb(event, callback->data);
return 0;
}
我知道回调使用函数指针来存储函数的地址。但是有几件事我发现我不明白:
- “注册回调”和“事件调度程序”是什么意思?
最佳答案
此代码使用 -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;
}
您可能需要检查回调函数是否获取了整个 struct event_cb - 通常,您只是传递数据,因为如前所述,否则您有相同信息的两个来源(以及指向您所在函数的指针)。可以对此进行大量清理 - 但它确实有效。
评论中的一个问题是:这是回调的一个很好的例子吗?
简而言之,没有 - 但部分原因是这里没有足够的基础设施。
在某种意义上,您可以将传递给qsort()
或bsearch()
函数的比较函数视为回调。它是一个指向传递给泛型函数的函数的指针,泛型函数可以完成泛型函数自身不能做的事情。
回调的另一个例子是信号处理函数。您告诉系统在事件(信号)发生时调用您的函数。您提前设置机制,以便当系统需要调用一个函数时,它知道要调用哪个函数。
示例代码试图提供一种更精细的机制 - 带有上下文的回调。在 C++ 中,这可能是一个仿函数。
我使用的一些代码对内存管理有非常挑剔的要求 - 当在特定上下文中使用时。因此,对于测试,我使用 malloc()
等,但在生产中,我必须将内存分配器设置为专用分配器。然后我在包中提供了一个函数调用,这样繁琐的代码就可以用它自己的代理版本覆盖默认的内存分配器——如果代理工作正常,代码将像以前一样运行。这些是回调的一种形式 - 同样,一种不需要太多(或任何东西)用户上下文数据的形式。
窗口系统具有已注册的事件处理程序(回调),GUI 主事件循环将在事件发生时调用。这些通常需要用户上下文以及 GUI 系统提供的特定于事件的信息。
关于c - C 中的函数指针和回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/631273/