SWIG+c+Python: Passing and receiving c arrays

匿名 (未验证) 提交于 2019-12-03 01:00:01

问题:

I am trying to reuse some old c code with SWIG and Python. Right now I am quite confused. The errors I get can be demonstrated on a small example:

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"] ) 

The example Python file "pybsp.py":

import bsp  a = [1, 1] b = [1, 1] c = []  bsp.add(a, b, c)  print(c) 

And I get the error:

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 []' 

Now, why I am confused is that the SWIG Documentation says: "C/C++ pointers are fully supported by SWIG. Furthermore, SWIG has no problem working with incomplete type information."

I also tried to add

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

to my .i file, which was recommended in this context, without success. My guess is, that I have to create a pointer like object in Python to pass, but I don't know how that works and also hope, that there is a simpler way.

Thank you very much for your help!

P.S.: As you might guess, this is my first contact with SWIG, so, unfortunately, I was not able to deduce the solution from solutions of seemingly similar problems.

EDIT: I found out that for arrays with given dimensions, as above, NumPy seems to be a good option to avoid the wrapping by hand. Basic examples are given here. Accordingly I changed my function definition to

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

Now the wrapper seems to have a chance to convert the NumPy array into a C array.

i-File

%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"]       ) 

And finally the python script, where I wanted to use int32 to avoid a type conversion Error (int64 -> int32) from NumPy

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) 

Now I got rid of the previous Error, but I have a new one:

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

Any suggestions?

回答1:

A Python list is quite different from a C array. In C the name of an array is a pointer to a contiguous block of memory containing its elements. Python lists are complicated datastructures where memory isn't contiguous and simple address calculations do not hold. So you cannot expect C code meant for C arrays to work with Python lists.

You can access Python lists from C as described here:

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



回答2:

Alright, now I have it. As written in the EDIT above, with numpy.i the arrays can be wrapped quite comfortably. What I did not see was, that the ARGOUT Array does not want an array as Input, as in C. There is just the dimension needed. So, with the Code above, the Script

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) 

Gives the desired Output

[2 2] 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!