简体   繁体   中英

Cython return malloced pointer from function

I am fairly new to Cython, so this is probably fairly trivial, but I haven't been able to find the answer anywhere.

I've defined a struct type and I want to write a function that will initialize all the fields properly and return a pointer to the new struct.

from cpython.mem import PyMem_Malloc


ctypedef struct cell_t:
    DTYPE_t[2] min_bounds
    DTYPE_t[2] max_bounds
    DTYPE_t size

    bint is_leaf
    cell_t * children[4]

    DTYPE_t[2] center_of_mass
    UINT32_t count


cdef cell_t * make_cell(DTYPE_t[2] min_bounds, DTYPE_t[2] max_bounds):
    cdef cell_t * cell = <cell_t *>PyMem_Malloc(sizeof(cell_t)) # <- Fails here
    if not cell:
        MemoryError()

    cell.min_bounds[:] = min_bounds
    cell.max_bounds[:] = max_bounds
    cell.size = min_bounds[0] - max_bounds[0]
    cell.is_leaf = True
    cell.center_of_mass[:] = [0, 0]
    cell.count = 0

    return cell

However, when I try to compile this, I get the following two errors during compilation:

cdef cell_t * make_cell(DTYPE_t[2] min_bounds, DTYPE_t[2] max_bounds):
    cdef cell_t * cell = <cell_t *>PyMem_Malloc(sizeof(cell_t))
                        ^
Casting temporary Python object to non-numeric non-Python type
------------------------------------------------------------

cdef cell_t * make_cell(DTYPE_t[2] min_bounds, DTYPE_t[2] max_bounds):
    cdef cell_t * cell = <cell_t *>PyMem_Malloc(sizeof(cell_t))
        ^
Storing unsafe C derivative of temporary Python reference
------------------------------------------------------------

Now, I've looked all over, and from what I can gather, cell is actually stored in a temporary variable that gets deallocated at the end of the function.

Any help would be greatly appreciated.

cell.min_bounds = min_bounds

This doesn't do what you think it does (although I'm not 100% sure what it does do). You need to copy arrays element by element:

cell.min_bounds[0] = min_bounds[0]
cell.min_bounds[1] = min_bounds[1]

Same for max_bounds .

The line that I suspect is giving you that error message is:

cell.center_of_mass = [0, 0]

This is trying to assign a Python list to a C array (remembering that arrays and pointers are somewhat interchangeable in C), which doesn't make much sense. Again, you'd do

cell.center_of_mass[0] = 0
cell.center_of_mass[1] = 0

All this is largely consistent with the C behaviour that there aren't operators to copy whole arrays into each other, you need to copy element by element.


Edit:

However that's not your immediate problem. You haven't declared PyMem_Malloc so it's assumed to be a Python function. You should do

from cpython.mem cimport PyMem_Malloc

Make sure it's cimport ed, not import ed


Edit2:

The following compiles fine for me:

from cpython.mem cimport PyMem_Malloc

ctypedef double DTYPE_t

ctypedef struct cell_t:
    DTYPE_t[2] min_bounds
    DTYPE_t[2] max_bounds


cdef cell_t * make_cell(DTYPE_t[2] min_bounds, DTYPE_t[2] max_bounds) except NULL:
    cdef cell_t * cell = <cell_t *>PyMem_Malloc(sizeof(cell_t))
    if not cell:
        raise MemoryError()
    return cell

I've cut down cell_t a bit (just to avoid having to make declarations of UINT32_t ). I've also given the cdef function an except NULL to allow it to signal an error if needed and added a raise before MemoryError() . I don't think either of these changes are directly related to your error.

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