繁体   English   中英

Function C 中的指针和回调

[英]Function pointers and callbacks in C

我已经开始审查回调。 我在 SO 上找到了这个链接: 什么是 C 中的“回调”以及它们是如何实现的? 它有一个很好的回调示例,与我们在工作中使用的非常相似。 但是,我试图让它工作,但我有很多错误。

#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;
}

我知道回调使用 function 指针来存储 function 的地址。 但是有几件事我觉得我不明白:

  • “注册回调”和“事件调度程序”是什么意思?

此代码在带有 -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;
}

您可能需要检查回调 function 是否获取整个结构 event_cb - 通常,您只需传递数据,因为如所示,否则您有两个相同信息的来源(以及指向的指针的备用副本您所在的 function)。 可以对此进行很多清理 - 但它确实有效。


评论中的一个问题是:这是回调的一个很好的例子吗?

简而言之,没有——但部分原因是这里没有足够的基础设施。

在某种意义上,您可以将传递给qsort()bsearch()函数的比较 function 视为回调。 它是一个指向 function 的指针,它被传递到通用 function 中,它执行通用 function 无法为自己做的事情。

回调的另一个示例是信号处理程序 function。 当事件(信号)发生时,您告诉系统调用您的 function。 您提前设置了机制,以便当系统需要调用 function 时,它知道要调用哪个 function。

示例代码试图提供一种更精细的机制——带有上下文的回调。 在 C++ 中,这可能是一个仿函数。

我使用的一些代码对 memory 管理有非常挑剔的要求——当在特定上下文中使用时。 因此,为了测试,我使用malloc()等,但在生产中,我必须将 memory 分配器设置为专用分配器。 然后我在 package 中提供了一个 function 调用,以便繁琐的代码可以覆盖默认的 memory 代码将在分配器之前使用它自己的代理工作,并且提供版本之前的分配器。 这些是回调的一种形式——同样,一种不需要太多(或任何东西)用户上下文数据的形式。

窗口系统具有已注册的事件处理程序(回调),并且 GUI 主事件循环将在事件发生时调用。 这些通常需要用户上下文以及 GUI 系统提供的特定于事件的信息。

“注册回调”和“事件调度程序”是什么意思?

“注册回调”是告诉底层系统调用哪个精确的 function,以及(可选)使用哪些参数,以及可能还针对哪个特定的 class 事件应该调用回调的行为。

“事件调度程序”从操作系统(或 GUI 等)接收事件,并通过查看已注册回调列表以查看哪些对该事件感兴趣,从而实际调用回调。

没有编译器 output 这很难,但我可以看到一些问题;

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);

您不能将类型(“事件”)的名称传递给 function,您必须传递该类型的实例。

int event_cb_register(event_ct_t cb, void *user_data);

那是什么类型event_ct_t 你的意思是event_cb_t吗?

struct event_cb *callback;

创建指向结构event_cb的未初始化指针。 请注意,这主要指向垃圾。

callback->cb(event, callback->data);

你试图称之为垃圾。 你需要初始化:

struct event_cb callback;
callback.cb = my_event_cb;
callback.data = 42;

或一些这样的东西。

您创建了您声明的结构的指针,但它不指向任何东西:

struct event_cb *callback;

您应该只创建一种结构类型:

struct event_cb callback;

然后将其地址传递给函数。

注册回调意味着您指定在感兴趣的事件发生时应该调用哪个 function。 基本上你在注册回调时设置 function 指针。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM