简体   繁体   English

SWIG C-to-Python Int Array

[英]SWIG C-to-Python Int Array

I am trying to access a C function with the following prototype from python using swig: 我试图使用swig从python中使用以下原型访问C函数:

int cosetCoding(int writtenDataIn, int newData, const int memoryCells, int *cellFailure, int failedCell);

Swig creates the .so with no problems and I can import it into python, but when I try to access it with the following: Swig创建.so没有问题,我可以将它导入到python中,但是当我尝试使用以下内容访问它时:

 cosetCoding.cosetCoding(10,11,8,[0,0,0,0,0,0,0,0],0)

I get the following traceback: 我得到以下回溯:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: in method 'cosetCoding', argument 4 of type 'int *'

The pointer is supposed to be an int array with size defined by memoryCells 指针应该是一个int数组,其大小由memoryCells定义

Use ctypes if you can. 如果可以,请使用ctypes。 It is simpler. 它更简单。 However, since you asked for SWIG, what you need is a typemap describing how to handle the int*. 但是,既然你要求SWIG,你需要的是一个描述如何处理int *的类型映射。 SWIG doesn't know how many integers may be pointed to. SWIG不知道可以指出多少个整数。 Below is hacked from an example in the SWIG documentation on multi-argument typemaps : 以下是关于多参数类型地图的SWIG文档中的示例:

%typemap(in) (const int memoryCells, int *cellFailure) {
  int i;
  if (!PyList_Check($input)) {
    PyErr_SetString(PyExc_ValueError, "Expecting a list");
    return NULL;
  }
  $1 = PyList_Size($input);
  $2 = (int *) malloc(($1)*sizeof(int));
  for (i = 0; i < $1; i++) {
    PyObject *s = PyList_GetItem($input,i);
    if (!PyInt_Check(s)) {
        free($2);
        PyErr_SetString(PyExc_ValueError, "List items must be integers");
        return NULL;
    }
    $2[i] = PyInt_AsLong(s);
  }
}

%typemap(freearg) (const int memoryCells, int *cellFailure) {
   if ($2) free($2);
}

Note that with this definition, when called from Python leave out the memoryCells parameter and just pass an array such as [1,2,3,4] for cellFailure . 请注意,使用此定义时,从Python调用时,请省略memoryCells参数,并为memoryCells传递[1,2,3,4]cellFailure The typemap will generate the memoryCells parameter. typemap将生成memoryCells参数。

PS I can post a fully working example (for Windows) if you want it. PS我可以发布一个完整的工作示例(对于Windows),如果你想要它。

Mark is right, you'll need a typemaps. 马克是对的,你需要一个打字机。 However, there's no need to code the typemap by hand if you use numpy.i (http://docs.scipy.org/doc/numpy/reference/swig.interface-file.html), which already defines the necessary typemaps to turn C into NumPy arrays and vice versa. 但是,如果使用numpy.i (http://docs.scipy.org/doc/numpy/reference/swig.interface-file.html),则无需手动编写类型映射,已经定义了必要的类型映射到将C转换为NumPy数组,反之亦然。

In your case (assuming cellFailure is an input array) you'll want to use 在你的情况下(假设cellFailure是一个输入数组)你将要使用

%apply (int DIM1, int* IN_ARRAY1) {(int memoryCells, int *cellFailure)}

Note (as Mark already pointed out) that this conveniently fuses these 2 parameters in C to a single python array parameter, no need to pass the array length separately. 注意(正如Mark已经指出的那样)这样可以方便地将C中的这2个参数融合到单个python数组参数中,无需单独传递数组长度。 Your call will look like: 您的电话将如下所示:

from numpy import asarray
cosetCoding.cosetCoding(10,11,asarray([0,0,0,0,0,0,0,0]),0)

You need to construct an array of c_int for that to work: 您需要构造一个c_int数组才能工作:

arr = (ctypes.c_int * 8)(0, 0, 0, 0, 0, 0, 0, 0)
cosetCoding.cosetCoding(10, 11, 8, arr, 0)

Updated Adding a more complete example. 更新添加更完整的示例。 I'm using ctypes version 1.1.0 under Python 2.6; 我在Python 2.6下使用ctypes 1.1.0版; perhaps we're doing something slightly differently? 也许我们做的事情略有不同?

Maybe pass ctypes.byref(arr) instead? 也许通过ctypes.byref(arr)代替?

cosetCoding.cosetCoding(10, 11, 8, ctypes.byref(arr), 0)

Here's what I tested with: 这是我测试的内容:

Shared object: cosetCoding.c 共享对象: cosetCoding.c

#include <stdio.h>
int cosetCoding(int writtenDataIn, int newData, const int memoryCells, int *cellFailure, int failedCell)
{
     printf("cellFailure: %d %d\n", cellFailure[0], cellFailure[1]);
}

Compile: 编译:

% gcc -shared -fPIC -o cosetCoding.so cosetCoding.c

Python script: test_coset.py Python脚本: test_coset.py

import ctypes
cosetCoding = ctypes.cdll.LoadLibrary('./cosetCoding.so')
arr = (ctypes.c_int * 8)(1, 2, 3, 4, 5, 6, 7, 8)
cosetCoding.cosetCoding(10, 11, 8, arr, 0)

Output: 输出:

% python test_coset.py
cellFailure: 1 2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM