Является ли хорошей идеей помещать определяемые пользователем типы в прототипы обратного вызова? - PullRequest
0 голосов
/ 05 августа 2011

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

Главное, что я хочу знать, действительно ли это хорошая идея, или это всего лишь хорошая идея, но похожая на Армагеддон.

Ответы [ 2 ]

2 голосов
/ 05 августа 2011

Если есть две библиотеки, использующие вашу библиотеку, которые обе определили UserDataForFooCallback как другую структуру, это нарушение правила одного определения. Просто придерживайтесь void*.

1 голос
/ 05 августа 2011

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

Обратите внимание, что это C-способ реализации этого.Если вы используете C ++, вы можете создать базовый класс и наследовать его.Конечно, аргумент вашего обратного вызова должен быть базовым классом.

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