SWIG + c + Python:传递和接收c数组

时间:2016-03-25 15:03:00

标签: python c++ c swig

我正在尝试使用SWIG和Python重用一些旧的c代码。 现在我很困惑。我得到的错误可以通过一个小例子来证明:

bsp.h:

extern void add(int a[], int b[], int c[]);

bsp.c:

#include "bsp.h" 
void add(int a[], int b[], int c[]) 
{ 
    c[0] = a[0] + b[0]; 
    c[1] = a[1] + b[1]; 
}

bsp.i

%module bsp
%{
    #include "bsp.h";
%}
%include "bsp.h";

setup.py:

#!/usr/bin/env python

from distutils.core import setup, Extension

bsp_module = Extension('_bsp',
    sources = ['bsp_wrap.c', 'bsp.c']
)

setup(name = 'bsp',
    ext_modules = [bsp_module],
    py_modules = ["bsp"]
)

示例Python文件" pybsp.py":

import bsp

a = [1, 1]
b = [1, 1]
c = []

bsp.add(a, b, c)

print(c)

我收到错误:

Traceback (most recent call last):
    File "pybsp.py", line 31, in <module>
    bsp.add(a, b, c)
TypeError: in method 'add', argument 1 of type 'int []'

现在,为什么我感到困惑的是SWIG Documentation说: &#34; SWIG完全支持C / C ++指针。此外,SWIG使用不完整的类型信息没有问题。&#34;

我也尝试添加

%apply int * INPUT { int *a}
%apply int * INPUT { int *b}
%apply int * OUTPUT { int *c}

到我的.i文件,这是在这种情况下推荐的,没有成功。 我的猜测是,我必须在Python中创建一个像对象一样的指针才能通过,但我不知道它是如何工作的,也希望有一种更简单的方法。

非常感谢你的帮助!

P.S。:正如您可能猜到的,这是我与SWIG的第一次联系,所以,不幸的是,我无法从似乎相似问题的解决方案中推断出解决方案。

修改 我发现对于具有给定尺寸的阵列,如上所述,NumPy似乎是避免手工包装的好选择。 给出了基本示例here.因此我将函数定义更改为

void add(int* a, int dim_a, int *b, int dim_b, int *c, int dim_c)

现在包装器似乎有机会将NumPy数组转换为C数组。

I-文件

%module bsp
%{
    #define SWIG_FILE_WITH_INIT
    #include "bsp.h"
%}

%include "numpy.i"

%init %{
    import_array();
%}

%apply (int* IN_ARRAY1, int DIM1){(int* a, int dim_a), (int* b, int dim_b)}
%apply (int* ARGOUT_ARRAY1, int DIM1){(int* c, int dim_c)}

%include "bsp.h"

setup.py

#!/usr/bin/env python

from distutils.core import setup, Extension
import numpy

try:
        numpy_include = numpy.get_include()
except AttributeError:
        numpy_include = numpy.get_numpy_include()

bsp_module = Extension('_bsp',
                       sources=['bsp_wrap.c', 'bsp.c'],
                       include_dirs=[numpy_include]
                       )

setup(name='bsp',
      ext_modules=[bsp_module],
      py_modules=["_bsp"]
      )

最后是python脚本,我想使用int32来避免NumPy中的类型转换错误(int64 - &gt; int32)

import bsp
import numpy as np
a = np.array([1, 1], dtype=np.int32)
b = np.array([1, 1], dtype=np.int32)
c = np.array([1, 1], dtype=np.int32)

bsp.add(a, b, c)

print(c)

现在我摆脱了之前的错误,但我有一个新错误:

  File "pybsp.py", line 10, in <module>
    bsp.add(a, b, c)
TypeError: Int dimension expected.  'unknown type' given.

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

Python列表与C数组完全不同。在C中,数组的名称是指向包含其元素的连续内存块的指针。 Python列表是复杂的数据结构,其中内存不是连续的,并且简单的地址计算不成立。因此,您不能指望C代码的C代码可以与Python列表一起使用。

您可以按照此处所述访问C中的Python列表:

http://effbot.org/zone/python-capi-sequences.htm

答案 1 :(得分:1)

好的,现在我拥有它。正如在上面的编辑中所写,使用numpy.i可以非常舒适地包装数组。我没有看到的是,ARGOUT数组不希望数组作为输入,如在C中。只需要维度。所以,使用上面的代码,脚本

import bsp
import numpy as np
a = np.array([1, 1], dtype=np.int32)
b = np.array([1, 1], dtype=np.int32)

c = bsp.add(a, b, np.shape(a)[0])

print(c)

提供所需的输出

[2 2]