【发布时间】:2012-05-06 21:13:29
【问题描述】:
我定义了一个struct a { }。我的 C 函数通过引用获取 struct a 数组,然后在其中填充数据。所以它接受一个参数struct a **。我想使用 SWIG 接口从 Python 调用此函数。有没有办法做到这一点?
【问题讨论】:
我定义了一个struct a { }。我的 C 函数通过引用获取 struct a 数组,然后在其中填充数据。所以它接受一个参数struct a **。我想使用 SWIG 接口从 Python 调用此函数。有没有办法做到这一点?
【问题讨论】:
您可以使用 SWIG 和 Python 做到这一点。我已经设置了以下 test.h 文件来演示:
struct a {
int val;
};
static void populate(struct a **list) {
int count = 0;
// Terminate when NULL entry found
while (*list) {
(*list)->val = count++;
++list;
}
}
populate 函数采用您所描述的 struct a**,假设列表以 NULL 结尾并对列表的每个元素执行某些操作。
我选择将它暴露给 Python 的方式是作为一个函数,它接受一个整数,即要使用的列表的大小,然后返回结果列表,因为这是映射“通过参数返回”在我看来设置。
我设置了一个基本的模块文件:
%module test
%{
#include "test.h"
%}
然后添加了一个类型映射,该类型映射根据指定给 Python 函数的大小准备输入列表:
%typemap(in,numinputs=1) struct a ** (int len=0) {
len = (int)PyInt_AsLong($input);
$1 = malloc(sizeof(struct a*)*(len+1));
$1[len] = NULL;
for (int i = 0; i < len; ++i) {
$1[i] = malloc(sizeof(struct a));
}
}
基本上,它将参数视为一个整数,为指针数组分配内存,然后为元素本身指向的对象分配一些内存。 (我单独分配它们以便 SWIG/Python 可以单独处理每个项目的引用计数,这比为所有元素分配一个块更简单)
编写完该类型图后,我添加了另一个类型图,它负责获取调用函数的结果并将其转换回 PyList:
%typemap(argout) struct a ** {
// Push into PyList for return
$result = PyList_New(len$argnum);
for (int i = 0; i < len$argnum; ++i) {
PyObject *element = SWIG_NewPointerObj(SWIG_as_voidptr($1[i]), SWIGTYPE_p_a, SWIG_POINTER_OWN);
PyList_SET_ITEM($result, i, element);
}
}
它利用了我们在 in 类型映射中创建的 len 变量,尽管由于它是 NULL 终止的,我们可以再次计算长度。然后,我们为传递给populate 函数的每个struct a 填充一个包装对象(由SWIG/Python 拥有)的Python 列表中的每个项目。请注意,如果类型名称不同,您需要将SWIGTYPE_p_a 更改为适当的SWIGTYPE。 (这些可以从生成的包装源中找到)。
最后,我们需要为 C 端的列表释放内存,使用:
%typemap(freearg) struct a ** {
free($1);
}
然后让 SWIG 使用这些类型映射来包装头文件本身:
%include "test.h"
我编译了这个:
痛饮 -python -Wall test.i gcc -Wall -Wextra test_wrap.c -I/usr/include/python2.6 -o _test.so -std=c99 -shared然后运行以下 Python 进行检查:
import test
r=test.populate(100)
print r[0].val
这个例子有几点需要注意:
test.populate("Hello world") 会做坏事,PyList_New 可能会失败,如果确实失败了,我们需要释放单个元素,而不仅仅是列表SWIG_POINTER_OWN
numinputs=1 更改为 0 并在 in 类型映射中相应地设置 len .编译/运行此示例所需的所有代码都包含在此答案中,但如果您希望将其放在一个方便的 tarball 中,我也将其放在 on my site 中。即使该链接应该断开,答案仍然有效。
【讨论】: