将用户可定义的类型放入回调原型是一个好主意吗?

时间:2011-08-05 14:39:34

标签: c types

为了提高某些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 个答案:

答案 0 :(得分:2)

如果有两个库使用您的库,它们都将UserDataForFooCallback定义为不同的结构,则它是一个定义规则违规。坚持使用void*

答案 1 :(得分:1)

如果您不关心用户数据的类型,则可以始终使用void *。然后人们可以发送他们想要的任何数据。

请注意,这是实现它的C方式。如果您正在使用C ++,则可以创建基类并从中派生。当然,你的回调参数应该是基类。