包装函数指针

时间:2015-08-11 03:52:36

标签: c

我正在尝试包装一个用于移植目的的库。该库公开了一个函数 - < - p>

fooLib(int , char , function pointer A);

函数指针A的签名是

void handler(DataFormat);

其中DataFormat是结构

我不希望我的包装器公开这个库的回调函数。我想创建一个不同的函数,应该由我的包装器的使用者使用,比如说

int handlerNew(NewDataFormat);

其中NewDataFormat是我的结构

现在的问题是如何将这两个功能联系起来?每当图书馆调用handler时,我希望它在填写handlerNew的{​​{1}}结构后调用我的回调NewDataFormat

1 个答案:

答案 0 :(得分:5)

只要您不需要线程安全,这并不难。您只需要提供一个私有(静态)处理程序和库的接口,它将库数据结构转换为您的包装版本,然后使用它作为参数调用您的回调。您的界面将如下所示:

// wrapped_foo_lib.h
typedef struct { ... } NewDataFormat;
typedef void (*WRAPPED_CALLBACK)(NewDataFormat);
void wrappedFooLibCall(int x, char c, WRAPPED_CALLBACK cb);

您的实施,客户永远不会看到:

// wrapped_foo_lib.c
// This static var makes this module _not_ thread safe.
static WRAPPED_CALLBACK wrapped_callback;

static void private_handler(DataFormat data) {
  NewDataFormat new_data = ...; // extract new_data from data
  wrapped_callback(new_data);
}

void wrappedFooLibCall(int x, char c, WRAPPED_CALLBACK cb) {
  wrapped_callback = cb;      
  foo_lib(x, c, private_handler);
}

非线程安全性是每个API回调应包含您要定义的void *的原因,并将其传递给回调。即您带家具的图书馆定义为

fooLib(int, char, void (*)(DataFormat, void *env));
void handler(DataFormat, void *env);

现在当你致电fooLib时,你提供任何结构env,然后它会传回给你。这样就可以省去包装器中的静态变量:

// wrapped_foo_lib.c
typedef struct { WRAPPED_CALLBACK wrapped_callback; } ENV;

static void private_handler(DataFormat data, void *void_env) {
  ENV *env = (ENV*)void_env;
  NewDataFormat new_data = ...; // extract new_data from data
  env->wrapped_callback(new_data);
}

void wrappedFooLibCall(int x, char c, WRAPPED_CALLBACK cb) {
  ENV env[1] = {{ cb }};      
  foo_lib(x, c, env);
}

这是线程安全的,因为ENV是堆栈分配的。一个很好的例子就是libpng。

随意将C90更新为更现代的语法。