如何在C中实现回调函数?

时间:2010-05-08 14:59:11

标签: c

gcc 4.4.3 c89

我正在创建一个客户端服务器应用程序,我需要实现一些回调函数。

但是,我在回调方面经验不足。我想知道是否有人知道在设计回调时要遵循的一些好的参考资料。是否有任何用于c的设计模式。我确实看过一些模式但是那里有所有的c ++。

非常感谢任何建议,

3 个答案:

答案 0 :(得分:4)

这是一个非常粗略的例子。请注意,我唯一要证明的是回调的使用,它的设计是为了提供信息,而不是演示。

假设我们有一个库(或任何围绕结构的函数集),我们将会看到与此类似的代码(当然,我将其命名为foo):

typedef struct foo {
     int value;
     char *text;
} foo_t;

这很简单。然后我们(通常)提供一些分配和释放它的方法,例如:

foo_t *foo_start(void)
{
    foo_t *ret = NULL;

    ret = (foo_t *)malloc(sizeof(struct foo));
    if (ret == NULL)
        return NULL;

    return ret;
}

然后:

void foo_stop(foo_t *f)
{
   if (f != NULL)
     free(f);
}

但是我们想要一个回调,所以我们可以定义一个函数,当foo->text有要报告的内容时输入该函数。为此,我们使用一个类型化的函数指针:

typedef void (* foo_callback_t)(int level, const char *data);

我们还希望任何foo系列函数都能够方便地输入此回调。要做到这一点,我们需要将它添加到结构中,现在看起来像这样:

typedef struct foo {
     int value;
     char *text;
     foo_callback_t callback;
} foo_t;

然后我们编写实际输入的函数(使用我们的回调类型的相同原型):

void my_foo_callback(int val, char *data)
{
    printf("Val is %d, data is %s\n", val, data == NULL ? "NULL" : data);
}

然后我们需要写一些方便的方法来说明它实际指向的功能:

void foo_reg_callback(foo_t *f, void *cbfunc)
{
    f->callback = cbfunc;
}

然后我们的其他foo函数可以使用它,例如:

int foo_bar(foo_t *f, char *data)
{
    if (data == NULL)
       f->callback(LOG_ERROR, "data was NULL");
}

请注意以上内容:

f->callback(LOG_ERROR, "data was NULL");

就像这样做:

my_foo_callback(LOG_ERROR, "data was NULL"):

除此之外,我们通过我们之前设置的函数指针输入my_foo_callback(),从而使我们可以灵活地定义我们自己的处理程序(如果/ as,甚至可以切换处理程序)需要)。

回调(甚至上面的代码)的最大问题之一是使用它们时的类型安全性。许多回调将采用void *指针,通常命名为context,可以是任何类型的数据/内存。这提供了很大的灵活性,但如果您的指针远离您,则可能会出现问题。例如,您不希望通过分配意外地将struct *实际上归为char *(或int。您可以传递的不仅仅是简单的字符串和整数 - 结构,联合,枚举等都可以传递。 CCAN的type safe callbacks帮助你在这样做的时候避免不知不觉中的邪恶演员(来自void *)。

同样,这是一个过于简化的示例,旨在向您概述使用回调的一种可能方法。请考虑它只是作为一个例子的伪代码。

答案 1 :(得分:3)

IN C,回调是通过函数指针完成的。

您绝对需要的一个功能是用户定义的上下文。您的代码使用void *指针并使其可用于回调函数:

void callback(..., void *ctx);

void call_service_which_invokes_callback(...,
                                         void (*cb)(..., void *ctx),
                                         void *ctx);

这样,回调可以访问任何必要的状态,而不必使用全局变量。

答案 2 :(得分:2)

C中的回调是使用函数指针实现的。这可能对起点有帮助:

What is a "callback" in C and how are they implemented?

此外,

http://www.newty.de/fpt/callback.html#howto