Чтобы повысить безопасность типов в некотором коде библиотеки C, у меня появилась идея использовать определяемые пользователем типы в функциях обратного вызова. Поэтому вместо переноса void*
в коде используется Usertype*
. Библиотека только объявляет тип, но не определяет его, и использует этот тип в качестве непрозрачного указателя. Вместо обычной схемы, когда библиотека определяет все используемые типы, части, которые используются в функциях обратного вызова, объявляются вперед и оставляются на усмотрение пользователя.
/*library code*/
struct UserDataForFooCallback; /* opaque user datatype */
typedef void CallbackFn(int i, struct UserDataForFooCallback* user);
void foo(CallbackFn* callback, struct UserDataForFooCallback* user)
{
callback(42, user);
}
/*application code*/
#include <stdio.h>
#include "foo.h"
struct UserDataForFooCallback
{
int a;
};
static void fooCallback(int i, struct UserDataForFooCallback* user)
{
printf(user->a == i ? "ok\n" : "fail\n");
}
int main()
{
struct UserDataForFooCallback cbd = {42};
foo(fooCallback, &cbd);
return 0;
}
Преимущества:
- Тип безопасных обратных вызовов
- нет
struct MyFoo* data=arg
присвоения указателя в коде обратного вызова
Недостатки:
- AFAIK не должно быть более одного определения определенного пользователем типа данных (или я смешиваю это с одним правилом определения C ++?), Что делает их проблематичными, если существует более чем использование функции обратного вызова ( скажем
foo
в примере используется разные части программы)
- Необходимость определения нового типа для каждого обратного вызова / группы обратных вызовов (возможно, это не так важно, так как многие функции обратного вызова уже используют один)
Главное, что я хочу знать, действительно ли это хорошая идея, или это всего лишь хорошая идея, но похожая на Армагеддон.