2010-05-08 2 views
4

gcc 4.4.3 c89Как реализовать функции обратного вызова в C?

Я создаю клиентское серверное приложение, и мне нужно будет реализовать некоторые функции обратного вызова.

Однако я не слишком опытен в обратных вызовах. И мне интересно, знает ли кто-нибудь о хороших справочных материалах при разработке обратных вызовов. Существуют ли какие-либо шаблоны проектирования, которые используются для c. Я просмотрел некоторые шаблоны, но там, где все C++.

Большое спасибо за любые предложения,

ответ

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() через функции указатель на что мы ранее установленного, тем самым предоставляя нам гибкость для определения нашего собственного обработчика «на лету» (и даже переключения обработчиков, если это необходимо).

Одна из самых больших проблем с обратными вызовами (и даже вышеприведенный код) - это безопасность при использовании при их использовании. Множество обратных вызовов будет принимать указатель void *, обычно называемый как context, который может быть любым типом данных/памяти. Это обеспечивает большую гибкость, но может быть проблематичным, если ваши указатели уйдут от вас. Например, вы не хотите случайно нарисовать то, что на самом деле struct *, как char * (или int, если на то пошло) по заданию. Вы можете передать гораздо больше, чем простые строки и целые числа - структуры, союзы, перечисления и т. Д. - все это можно передать. CCAN's type safe callbacks поможет вам избежать невольно злых бросков (до/от void *) при этом.

Опять же, это более упрощенный пример, призванный дать вам обзор одного из возможных способов использования обратных вызовов. Пожалуйста, обратите внимание на код psuedo, который предназначен только в качестве примера.

+0

большой .......... –

2

Callbacks в C реализованы с помощью указателей на функции. Это может быть полезно для отправных точек:

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

Кроме того,

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

+0

Безопасные помощники обратного вызова типа CCAN (http://ccan.ozlabs.org/info/typesafe_cb.html) также являются хорошим ресурсом, особенно для тех, кто не может быть достаточно опытным, чтобы избежать злых бросков при работе с большим количеством пустот указатели. –

3

IN C, обратные вызовы выполняются с помощью указателей функций.

Одна из особенностей, которую вы определенно хотите, - это контекст, определяемый пользователем. Ваш код занимает void * указатель и делает его доступным для функции обратного вызова:

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

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

Таким образом, обратный вызов может получить доступ к любой необходимой государству без необходимости использовать глобальные переменные.

Смежные вопросы