11

I am trying to access a C function with the following prototype from python using swig:

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:

 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

3 Answers 3

14

Use ctypes if you can. It is simpler. However, since you asked for SWIG, what you need is a typemap describing how to handle the int*. SWIG doesn't know how many integers may be pointed to. Below is hacked from an example in the SWIG documentation on multi-argument typemaps:

%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. The typemap will generate the memoryCells parameter.

P.S. I can post a fully working example (for Windows) if you want it.

Sign up to request clarification or add additional context in comments.

2 Comments

Tried this with SWIG, works great. Thanks! Since there's 3 replies all saying I should use ctypes though I'll prolly switch to that in the near future.
No need to code the typemaps by hand if you use numpy.i, see my answer.
8

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.

In your case (assuming cellFailure is an input array) you'll want to use

%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. Your call will look like:

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

1 Comment

Cool, I just started using numpy recently. Much easier.
2

You need to construct an array of c_int for that to work:

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; perhaps we're doing something slightly differently?

Maybe pass ctypes.byref(arr) instead?

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

Here's what I tested with:

Shared object: 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

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

4 Comments

Same error as before...arr is a: <__main__.c_int_Array_8 object at 0x7fdb9da9ad40> not a 'int *'
so I tried switching to ctypes from SWIG, and it'll import the .so and python doesn't complain about passing the parameters, but its returning the wrong value from the function. I tried this on another function and there was the same result (incorrect output).
scratch that, the problem is with my C program apparently for the cosetCoding function. So this works! yay! thanks! My function that is returning a double is still returning garbage though (strangely enough).
@Adam great to hear you're making progress!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.