2

I'm trying to call to a C function that accept a pointer to pointer and redirect it to a internally-allocated 1D array, something along that line:

typedef myStruct {
    const char* name;
    int status;
} myStruct;

int foo(const myStruct** array, size_t* size);

I'm trying to wrap it with Python and NumPy, and get a NumPy array that wraps that internal memory (as read-only).

I've got the following:

arr = np.ctypeslib.ndpointer(dtype=np.dtype([('name', np.intp),
                                             ('status', np.int)]))()
size = ct.c_size_t()
_call('foo', ct.byref(arr), ct.byref(size))
arr = np.ctypeslib.as_array(arr, shape=(size.value,))
arr.flags.writeable = False # not our memory!

Where _call() is a wrapper that check for the returned value.

I'm getting the following:

ValueError: '<P' is not a valid PEP 3118 buffer format string

over the call to as_array(). What am I doing wrong?


EDIT: My goal here is to read the data as NumPy structured array, as I think it's the best way to describe a C array of structs in python.

feedMe
  • 3,431
  • 2
  • 36
  • 61
galah92
  • 3,621
  • 2
  • 29
  • 55
  • Please check [\[SO\]: How to create a Minimal, Complete, and Verifiable example (mcve)](https://stackoverflow.com/help/mcve). Add all the missing parts of the code as the error might be in there. Also, *Python* version, *OS* would be useful as well. – CristiFati Dec 29 '18 at 10:11
  • _"Where _call() is a wrapper that check for the returned value."_ - note that you don't need to use this - ctypes lets you specify `_check_retval_` – Eric Jan 06 '19 at 22:52
  • Or via [`.errcheck`](https://docs.python.org/2/library/ctypes.html#ctypes._FuncPtr.errcheck) – Eric Jan 06 '19 at 23:07

1 Answers1

0

This could perhaps be viewed as a bug in ndpointer - the problem is that as_array checks to see if its argument is a pointer, but that test fails for ndpointer, and numpy tries to create an array containing a single pointer (which fails because numpy has no pointer type).

You can get by just fine without using numpy at all:

class myStruct(ctypes.Structure):
    _fields_ = [
        ('name', ctypes.c_char_p),
        ('status', ctypes.c_int),
    ]

arr = ctypes.POINTER(myStruct)()
size = ct.c_size_t()
_call('foo', ct.byref(arr), ct.byref(size))

# convert from `myStruct*` to `myStruct[size]`
arr = ctypes.cast(arr, ctypes.POINTER(myStruct * size.value)).contents

arr is now a ctypes array.

Eric
  • 95,302
  • 53
  • 242
  • 374