SWIG 将多个数组从 python 传递到 C

SWIG passing multiple arrays from python to C

使用 SWIG,我一直在尝试使用以下签名包装 C 函数:

void mainline(double *data, int datasize, char *metadata, int metasize, char *path)

python 调用者正在传递 numpy 1D 数组,所以(暂时忽略最终的 char *path),我想到了一个接口文件,例如:


%module testit

%{
#define SWIG_FILE_WITH_INIT
void mainline(double* dataPtr, int datasize, char* headerPtr, int headersize);
%}
%include "numpy.i"
%init %{
import_array();
%}
%apply (double* IN_ARRAY1 int DIM1) {(double* dataPtr, int datasize)}
%apply (char* IN_ARRAY1, int DIM1) {(char* headerPtr, int headersize)}

%inline %{
    void testit_mainline(double* dataPtr, int datasize, char* headerPtr, int headersize) {
        return mainline(dataPtr, datasize, headerPtr, headersize);
    }
%}

会做的。但是,当我从 python 调用

import testit
import numpy as np
dataPtr = np.zeros(5)
datasize = dataPtr.size
headerPtr = "Just testing"
headersize = len(headerPtr)
testit.testit_mainline(dataPtr,datasize,headerPtr,headersize)

我收到错误消息“testit_mainline() 需要 3 个位置参数,但给出了 4 个”?

果然,如果我查看生成的 c 包装器“testit_wrap.c”,我会看到如下行:

SWIGINTERN PyObject *_wrap_testit_mainline(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
...
...
PyObject *swig_obj[3] ;

尽管我的接口文件中有明显的 4 个参数。我哪里错了?

当您使用多参数类型映射时,多个 C 参数由一个 Python 参数表示。在这种情况下,单个 numpy 数组或 Python 列表可以用作指针和大小的参数,因为 Python 知道其对象的长度并且类型映射说明了这一点。

此外,错误需要 3 个参数,因为第二个数组没有正确匹配类型。 numpy.i documentation 表示支持 signed char,而不是 char(SWIG 可能很迂腐),所以我使用了它并且它与类型映射正确匹配并且只需要两个参数。

这是一个最小的例子:

test.i:

%module test

%{
#define SWIG_FILE_WITH_INIT
%}

%include "numpy.i"
%init %{
import_array();
%}

%apply (double* IN_ARRAY1, int DIM1) {(double* dataPtr, int datasize)}
%apply (signed char* IN_ARRAY1, int DIM1) {(char* headerPtr, int headersize)}

%inline %{
    void mainline(double* dataPtr, int datasize, char* headerPtr, int headersize) {
        for(size_t i = 0; i < datasize; ++i)
            printf("[%zu] %lf\n",i,dataPtr[i]);
        for(size_t i = 0; i < headersize; ++i)
            printf("[%zu] %hhd\n",i,headerPtr[i]);
    }
%}

输出:

>>> import test
>>> test.mainline([1.0,1.5,2.0],[1,2,3])
[0] 1.000000
[1] 1.500000
[2] 2.000000
[0] 1
[1] 2
[2] 3
>>> import numpy as np
>>> a = np.array([1.1,2.2,3.3])
>>> b = np.array([1,2,3],dtype=np.int8)
>>> test.mainline(a,b)
[0] 1.100000
[1] 2.200000
[2] 3.300000
[0] 1
[1] 2
[2] 3