How to pass numpy array inside of struct to ctypes function?

ctypes, numpy, python

Solution

You can remove `array_1d_double`. It is not needed.

The struct should be declared like this:

class MyStruct(ctypes.Structure):
    _fields_ = [
        ('n', ctypes.c_int),
        ('x', ctypes.POINTER(ctypes.c_double))
    ]

I've changed both types. You had `c_int16`, but the type you used in the C code is `int`. That maps to `c_int`. And likewise for the array, that is `double*`. In ctypes that is `POINTER(ctypes.c_double)`.

The struct should be initialised like this:

mystruct = MyStruct()
mystruct.n = len(x)
mystruct.x = npct.as_ctypes(x)

With these changes, your code works as intended.

Problem

I'm trying to wrap some third-party code from a library in my Python application. Essentially, the function I would like to call takes a struct as input that houses (among other things) pointers to double arrays. A simplified example would be: myfunc.h: ``` typedef struct mystruct_t { int n; double *x; } mystruct_t; double myfunc(mystruct_t* data); ``` myfunc.c: ``` #include "myfunc.h" double myfunc(mystruct_t* data) { double result = 0.; for(int i = 0; i < data->n; i++) { result += data->x[i]; } return result; } ``` Makefile: ``` CC = gcc CFLAGS = -g -Wall -fPIC -lm -std=gnu99 all: libmyfunc.so m.PHONY : clean libmyfunc.so: myfunc.o gcc -shared -Wl,-soname,$@ -o $@ $^ %.o: %.c $(CC) -c $(CFLAGS) $< clean: rm -vf libmyfunc.so *.o ``` I would like to wrap `myfunc` using NumPy, `ctypes.Structure` and `numpy.ctypeslib` so that I can pass NumPy arrays to `myfunc` as attributes of `mystruct_t`. So far I've been trying the following: myfunc.py: ``` #!/usr/bin/env python import numpy as np import numpy.ctypeslib as npct import ctypes import os array_1d_double = npct.ndpointer(dtype=np.double, ndim=1, flags='C_CONTIGUOUS') class MyStruct(ctypes.Structure): _fields_ = [ ('n', ctypes.c_int16), ('x', array_1d_double) ] libmyfunc = npct.load_library('libmyfunc', os.path.dirname(__file__)) libmyfunc.myfunc.restype = ctypes.c_double libmyfunc.myfunc.argtypes = [ ctypes.POINTER(MyStruct) ] x = np.array([1.0, 2.0, 3.0, 4.0]) mystruct = MyStruct() mystruct.n = len(x) mystruct.x = x res = libmyfunc.myfunc(mystruct) ``` However, this fails with the following error message: ``` $ python myfunc.py Traceback (most recent call last): File "./myfunc.py", line 26, in <module> mystruct.x = x TypeError: cannot be converted to pointer ``` How do I define my function signatures correctly so that type conversion can happen? Or do I need to convert `x` somehow before assigning it to `mystruct.x`? Unfortunately I cannot change the signature of the method I would like to call and I would like to not have to write wrapper C code unless it is absolutely necessary. The other questions and resources that I've found on this only deal with either `ctypes.Structure`s or `numpy.ctypeslib`, but can you make them work together? I've uploaded my reduced example as a gist so you can use it as a starting point. Many thanks in advance!

Original source