【发布时间】:2019-04-24 04:35:56
【问题描述】:
TL;DR 有人知道如何指示 SWIG 将 C-struct 的这些成员视为函数指针并使其可从 Python 调用吗?
全文 我有 C 结构,其中包含指向函数的指针。这些函数都是类型定义的。我有一个 C 函数,它将为此 C 结构分配内存,并将函数指针设置为指向有效的 C 函数。 我的简化头文件是这样的
// simplified api.h
typedef void *handle_t;
typedef void sample_t;
typedef error_t comp_close_t(handle_t *h);
typedef error_t comp_process_t(handle_t h,
sample_t *in_ptr,
sample_t *out_ptr,
size_t *nr_samples);
typedef struct
{
comp_close_t *close;
comp_process_t *process;
} audio_comp_t;
// prototype for init
error_t comp_init(handle_t *h, int size);
以及对应的简化源文件:
// simplified api.c
static comp_close_t my_close;
static comp_process_t my_process;
audio_comp_t comp = {
my_close,
my_process
};
error_t comp_init(audio_comp_t **handle) {
*handle = ∁
return 0;
}
error_t my_close(handle_t *h) {
// stuff
*h = NULL;
return 0;
}
error_t my_process(handle_t h,
sample_t *in_ptr,
sample_t *out_ptr,
size_t *nr_samples) {
audio_comp_t *c = (audio_comp_t*) h;
// stuff
printf("doing something useful\n");
}
还有我的接口文件的最新版本:
%module comp_wrapper
%{
#include "api.h"
%}
%include "api.h"
// Take care of the double pointer in comp_init
%ignore comp_init;
%rename(comp_init) comp_init_overload;
%newobject comp_init;
%inline %{
audio_comp_t* comp_init_overload(int size) {
audio_comp_t *result = NULL;
error_t err = comp_init(&result, size);
if (SSS_NO_ERROR == err) {
...
}
return result;
}
%}
// wrap the process call to verify the process_t * function pointer
%inline %{
sss_error_t call_process( audio_comp_t *h,
sample_t *in,
sample_t *out,
size_t nr_samples)
{
return h->process(h, in, out, &nr_samples);
}
%}
我想使用 SWIG 创建语言绑定,这样我就可以用最少的 Python 样板代码调用这些类似对象的结构。最终我想这样使用:
h = comp_init(50)
h.process(h, input_data, output_data, block_size)
h.close(h)
然而,SWIG 将这些结构中的这些函数指针视为对象,所以每当我想调用它们时,我都会得到
>>> h = comp_init(50)
>>> h.api.process()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'SwigPyObject' object is not callable
我可以通过你可以在接口文件中找到的“call_process”函数来解决它:
call_process(h, in, out, 32)
但这需要我为所有结构成员函数添加一个额外的包装器,虽然这不是必需的,因为 [SWIG 文档声明完全支持函数指针][1]
我假设我应该在接口文件中编写一些代码,以便 SWIG 知道它处理的是函数而不是 SwigPyObject
有一些关于如何处理(python)回调的信息,但在这种情况下似乎没有一个特别有效: SWIG call function pointers stored within struct
或者不将头文件中的所有信息或多或少地复制到接口文件中: Using SWIG with pointer to function in C struct
最后但并非最不重要的是,当您将函数指针包装在结构中时似乎有所不同,因此解决方案 5 不起作用: How to wrap a c++ function which takes in a function pointer in python using SWIG
有人知道如何指示 SWIG 将 C-struct 的这些成员视为函数指针并使其可从 Python 调用吗?
【问题讨论】:
-
您自己引用的示例stackoverflow.com/questions/1583293/… 考虑了一个带有函数指针成员的结构,并展示了如何从 Python 调用它。这与您尝试做的有什么不同
-
情况也一样。然而,解决方案并不是我希望的那样。必须在接口文件中重复每个与函数指针相关的结构和函数声明并不是最好的解决方案。在这种情况下,我不妨编写包装器来手动从 python 调用代码。我特别希望能够告诉 SWIG 使函数指针可调用。
-
SWIG 的功能远不止于此,您无需在如此低的级别上工作并使用裸指针进行强制转换。所有函数都可以被包装,它甚至可以生成一个运行时,可用于查询内容。我的建议是跳过
typedefed 函数原型并简单地包装实际函数。将被附在图书馆中。如果需要初始化,请在 *nix 或 Windows 中使用attribute(constructor)DLL_PROCESS_ATTACH -
如果你愿意的话,我这里有一个小项目,它做了很多工作,github.com/JensMunkHansen/sofus
-
我目前正在考虑解决方案,但现在我有一个快速的澄清点:
comp_process_t采用handle_t,但comp_close_t采用handle_t*?另外你愿意稍微编辑一下 api.h,而不是更改 C API,而是使用一些宏来简化 SWIG 界面吗?
标签: python c function struct swig