简体   繁体   中英

Wrapping C function in Cython and NumPy

I'd like to call my C function from Python, in order to manipulate some NumPy arrays. The function is like this:

void c_func(int *in_array, int n, int *out_array);

where the results are supplied in out_array, whose size I know in advance (not my function, actually). I try to do in the corresponding.pyx file the following, in order to able to pass the input to the function from a NumPy array, and store the result in a NumPy array:

def pyfunc(np.ndarray[np.int32_t, ndim=1] in_array):    
    n = len(in_array)
    out_array = np.zeros((512,), dtype = np.int32)
    mymodule.c_func(<int *> in_array.data, n, <int *> out_array.data)
    return out_array

But I get "Python objects cannot be cast to pointers of primitive types" error for the output assignment. How do I accomplish this?

(If I require that the Python caller allocates the proper output array, then I can do

def pyfunc(np.ndarray[np.int32_t, ndim=1] in_array, np.ndarray[np.int32_t, ndim=1] out_array):  
    n = len(in_array)
    mymodule.cfunc(<int *> in_array.data, n, <int*> out_array.data)

But can I do this in a way that the caller doesn't have to pre-allocate the appropriately sized output array?

You should add cdef np.ndarray before the out_array assignement:

def pyfunc(np.ndarray[np.int32_t, ndim=1] in_array):    
    cdef np.ndarray out_array = np.zeros((512,), dtype = np.int32)
    n = len(in_array)
    mymodule.c_func(<int *> in_array.data, n, <int *> out_array.data)
    return out_array

Here is an example how to manipulate NumPy arrays using code written in C/C++ through ctypes. I wrote a small function in C, taking the square of numbers from a first array and writing the result to a second array. The number of elements is given by a third parameter. This code is compiled as shared object.

squares.c compiled to squares.so:

void square(double* pin, double* pout, int n) {
    for (int i=0; i<n; ++i) {
        pout[i] = pin[i] * pin[i];
    }
}

In python, you just load the library using ctypes and call the function. The array pointers are obtained from the NumPy ctypes interface.

import numpy as np
import ctypes

n = 5
a = np.arange(n, dtype=np.double)
b = np.zeros(n, dtype=np.double)

square = ctypes.cdll.LoadLibrary("./square.so")

aptr = a.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
bptr = b.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
square.square(aptr, bptr, n)

print b

This will work for any c-library, you just have to know which argument types to pass, possibly rebuilding c-structs in python using ctypes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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