【问题标题】:How do I implement callback functions in C?如何在 C 中实现回调函数?
【发布时间】:2010-05-08 14:59:11
【问题描述】:

gcc 4.4.3 c89

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

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

非常感谢您的任何建议,

【问题讨论】:

    标签: c


    【解决方案1】:

    这是一个非常粗略的例子。请注意,我要演示的唯一内容是回调的使用,它旨在提供信息,而不是演示。

    假设我们有一个库(或任何围绕结构旋转的函数集),我们将拥有与此类似的代码(当然,我将其命名为 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(),从而使我们能够灵活地动态定义自己的处理程序(甚至根据需要切换处理程序) .

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

    同样,这是一个过于简化的示例,旨在让您大致了解一种使用回调的可能方式。请考虑它只是作为示例的伪代码。

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        【解决方案3】:

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

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

        还有,

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

        【讨论】:

        • CCAN 的类型安全回调助手 (ccan.ozlabs.org/info/typesafe_cb.html) 也是一个很好的资源,特别是对于那些在处理大量 void 指针时可能没有足够经验来避免恶意转换的人。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-07
        • 2011-09-25
        • 1970-01-01
        相关资源
        最近更新 更多