gcc 4.4.3 c89
我正在创建一个客户端服务器应用程序,我需要实现一些回调函数。
但是,我在回调方面经验不足。我想知道是否有人知道在设计回调时要遵循的一些好的参考资料。是否有任何用于c的设计模式。我确实看过一些模式但是那里有所有的c ++。
非常感谢任何建议,
答案 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)