无论perlcall(在"策略存储回调上下文信息"一节),并延伸和嵌入Perl(以下简称"回调"一节)列出了3点不同的方式来处理从XS/C调用的Perl子例程:
上面针对#3列出的示例和细节使用XS中的散列来将子ref与特定C函数相关联,但是它们预定义了固定数量的C函数,这是不合适的.
我正在使用一个XS接口到一个C库,它使用带有可选参数的回调/函数指针,例如:
blah(custom_type *o, void (*func) (void *data, int more_data), const void * data);
Run Code Online (Sandbox Code Playgroud)
这个库中的C blah将最终调用传递给它的函数以及传入的数据.
如果可能的话,我想将C API的一对一映射到Perl.例如
blah($o, \&func, $data);
Run Code Online (Sandbox Code Playgroud)
目前,我上面有#2,但是另一次调用blah()会覆盖已保存的SV*.
我将如何实施上述#3?
这是我想出的解决方案:
此 C 库中的大多数回调将采用用户提供的 void * 并将其作为第一个参数传递。所以我将 SV * 和用户提供的数据保存在一个结构中:
typedef struct __saved_callback {
SV *func;
void *data;
} _saved_callback;
Run Code Online (Sandbox Code Playgroud)
我的 XS 函数将分配一个 _saved_callback 结构,并将其作为第一个参数传递给 call_perl_sub() 以及 Perl 子引用和用户假设的数据。
void
blah(obj, func, data)
whatever *obj
void *func
void *data
CODE:
_saved_callback *sc = NULL;
Newx(sc, 1, _saved_callback);
sc->func = (SV *)func;
sc->data = data;
blah(obj, call_perl_sub, sc);
Run Code Online (Sandbox Code Playgroud)
然后调用 Perl 子引用(我省略了用户提供的数据参数的堆栈操作):
void call_perl_sub(void *data) {
dSP;
int count;
_saved_callback *perl_saved_cb = data;
count = call_sv(perl_saved_cb->func, G_DISCARD);
if ( count != 0 )
croak("Expected 0 value got %d\n", count);
}
Run Code Online (Sandbox Code Playgroud)