【发布时间】:2017-06-28 16:36:51
【问题描述】:
我正在使用 SWIG 为 Python 包装一个 C 库。其中一种 C 方法采用 指向结构缓冲区的指针以及要填充和填充的元素数量 指向的结构。对于 Python API,我只想提供 元素的数量和返回值是填充结构的元组。
C : int fill_widgets(widget_t *buffer, int num_widgets);
Python: fill_widgets(num_widgets) -> (widget, widget,...)
我已经编写了可以按我想要的方式工作的类型图 - 类型图分配 基于 Python 输入参数的缓冲区,将缓冲区传递给 C 方法, 将其转换为 Python 元组,然后返回小部件的元组。但我想不通 如果/何时/如何我需要释放在我的类型映射中分配的内存。
我最初包含一个 freearg 类型映射来在包装器时释放缓冲区 函数退出,但我相信返回给 Python 的结构仍在使用 物理内存(即没有复制内存,我只是得到一个代理指针 即使用相同的缓冲区)。我也尝试设置 SWIG_POINTER_OWN 标志 创建代理对象时(通过 SWIG_NewPointerObj),但因为我正在创建 指向缓冲区中每个元素的代理指针,释放它们没有意义 全部。在这两种情况下,Python 最终都会在稍后出现段错误 free() 调用。
因此,在创建代理时,无需在类型映射中使用 freearg 或 SWIG_POINTER_OWN, 当 Python tuple-of-structs 超出范围时如何释放内存?
这是一个简单的 SWIG 界面,演示了我所拥有的:
%module "test"
%typemap (in, numinputs=1) (BUF, NUM){
$2 = PyInt_AsLong($input);
$1 = ($1_type)calloc($2, sizeof($*1_type));
}
%typemap (argout) (BUF, NUM){
PyObject *tpl = PyTuple_New($2);
for ($2_ltype i=0; i<$2; i++)
{
PyTuple_SET_ITEM(tpl, i, SWIG_NewPointerObj(&$1[i], $1_descriptor, 0));
}
$result = SWIG_Python_AppendOutput($result, tpl);
}
%typemap (freearg) (BUF, NUM){
//free($1);
}
%apply (BUF, NUM) {(widget_t *buf, int num_widgets)};
%inline {
typedef struct {int a; int b;} widget_t;
int fill_widgets(widget_t *buf, int num_widgets)
{
for(int i=0; i<num_widgets; i++)
{
buf[i].a = i;
buf[i].b = 2*i;
}
return num_widgets;
}
}
以及构建/运行的示例:
$ swig -python test.i
$ gcc -I/path/to/python2.7 -shared -lpython2.7 test_wrap.c -o _test.so
$ python
>>> import test
>>> _,widgets = test.fill_widgets(4)
>>> for w in widgets: print w.a, w.b
...
0 0
1 2
2 4
3 6
>>>
C 中 fill_widgets 的示例用法:
int main()
{
widget_t widgets[10]; // or widget_t *widgets = calloc(10, sizeof(widget_t))
fill_widgets(widgets, 10);
}
【问题讨论】: