SWIG默认使用作为输出的double *参数做什么?

时间:2015-06-02 18:44:53

标签: swig

这是我第一次遇到SWIG,我没有通过搜索找到任何有用的东西,这可能意味着我甚至没有找到正确的方向。如果有人能让我受到影响,那就太好了。

我有一个C函数,它将double *作为参数并将其用作输出:

int myFunc(double* p, int len){
  int i;
  for(i=0; i<len; i++){
    p[i] = (double)i;
  }
return 0;
}

为了包装它,我没有做任何棘手或自定义的事情,我只是让SWIG做它默认做的事情:

%module MyModule
 %{
 /* Includes the header in the wrapper code */
 #include "MyModule.h"
 %}

 /* Parse the header file to generate wrappers */
 %include "MyModule.h"

这一切都是因为它编译并构建了一个我可以加载的模块。但是,有人可能会合理地期望能够像这样从Python中调用它,而且我不能:

numbers = [0.0]*5
myFunc(numbers, 5)

SWIG抱怨第一个参数是错误的类型。我一直在阅读有关typemaps.i的内容,它允许您手动指定类型转换。对于像这个例子那样标准的东西,这是否必要?如果有人能告诉我应该阅读的内容或Google的内容,我将不胜感激。

1 个答案:

答案 0 :(得分:0)

使用内置类型作为SWIG的输入参数会自动处理,但SWIG需要一些输出参数帮助。以下是一种简单的方法。

请注意,%inline是一种在.i文件中为其添加函数和SWIG包装的方法,而不是使用#include%include生成头文件。对于小例子来说这很好。

参考:carrays.i

%module x

%include <carrays.i>
%array_functions(double,doubles)

%inline %{
int myFunc(double* p, int len)
{
    int i;

    for(i = 0; i < len; i++)
        p[i] = (double)i;

    return 0;
}
%}

输出:

>>> import x
>>> pd=x.new_doubles(10)
>>> pd
<Swig Object of type 'double *' at 0x0000000002235CC0>
>>> x.myFunc(pd,10)
0
>>> x.doubles_getitem(pd,0)
0.0
>>> x.doubles_getitem(pd,1)
1.0
>>> x.doubles_getitem(pd,9)
9.0
>>> x.delete_doubles(pd)

通过更多工作,我们可以使用类型映射获得更多Pythonic界面。下面是一组in / argout / argfree类型映射,从单个Python输入对象生成类型C参数。

%typemap(in)定义了如何将Python输入转换为输入参数。它检查整数对象并生成第二个参数(len),然后使用malloc生成第一个参数。

%typemap(argout)定义了如何将输出参数转换为Python对象,并将其附加到由$result表示的现有返回值。

%typemap(free)in typemap中释放已分配的参数。

参考文献:Common typemap methodsMulti-argument typemaps

%module x
%include <exception.i>

%typemap(in) (double* p, int len) %{
    if(!PyLong_Check($input))
        SWIG_exception(SWIG_TypeError, "expected integer");
    $2 = PyLong_AsUnsignedLong($input);
    $1 = malloc($2 * sizeof(double));
%}

%typemap(freearg) (double* p, int len) %{
    free($1);
%}

%typemap(argout) (double* p, int len) {
    PyObject* list = PyList_New($2);
    int i;
    for(i = 0; i < $2; ++i)
        PyList_SET_ITEM(list, i, PyFloat_FromDouble($1[i]));
    $result = SWIG_Python_AppendOutput($result, list);
}

%inline %{
int myFunc(double * p, int len)
{
    int i;

    for(i = 0; i < len; i++)
        p[i] = (double)i;

    return 0;
}
%}

输出:

>>> import x
>>> x.myFunc(5)
[0, [0.0, 1.0, 2.0, 3.0, 4.0]]
>>> return_value, double_list = x.myFunc(3)
>>> return_value
0
>>> double_list
[0.0, 1.0, 2.0]