我正在尝试包装一个用于移植目的的库。该库公开了一个函数 - < - p>
fooLib(int , char , function pointer A);
函数指针A的签名是
void handler(DataFormat);
其中DataFormat
是结构
我不希望我的包装器公开这个库的回调函数。我想创建一个不同的函数,应该由我的包装器的使用者使用,比如说
int handlerNew(NewDataFormat);
其中NewDataFormat
是我的结构
现在的问题是如何将这两个功能联系起来?每当图书馆调用handler
时,我希望它在填写handlerNew
的{{1}}结构后调用我的回调NewDataFormat
。
答案 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更新为更现代的语法。