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

What does SWIG do by default with a double* argument that is an output?

这是我第一次接触 SWIG,我没有通过搜索找到任何有用的东西,这可能意味着我什至没有找到正确的方向。如果有人能帮我引导一下,那就太好了。

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

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 的目的,我将不胜感激。

使用内置类型作为 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.[=26= 表示的现有 return 值]

%typemap(free)in 类型映射中释放分配的参数。

参考文献:Common typemap methods, Multi-argument typemaps

%module x
%include <exception.i>

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

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

%typemap(argout) (double* p, int len) {
    PyObject* list = PyList_New();
    int i;
    for(i = 0; i < ; ++i)
        PyList_SET_ITEM(list, i, PyFloat_FromDouble([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]