我想对Cython使用一个小的C例程。 C函数本身是
#include <stdio.h>
#include "examples.h"
void add_array(int **io_array, int n) {
int i;
int *array;
array = (int *) malloc(n * sizeof(int));
for(i = 0; i < n; i++) {
array[i] = i;
}
*io_array = array;
}
和函数原型:
#ifndef EXAMPLES_H
#define EXAMPLES_H
void add_array(int **io_array, int n);
#endif
现在,我想使用Cython与以下C函数接口:
cdef extern from "examples.h":
void add_array(int **io_array, int n)
import numpy as np
def add(arr):
if not arr.flags['C_CONTIGUOUS']:
arr = np.ascontiguousarray(arr, dtype=np.int32)
cdef int[::1] arr_memview = arr
add_array(&arr_memview[0], arr_memview.shape[0])
return arr
编译时会出现错误:
pyexamples.pyx:13:14: Cannot assign type 'int *' to 'int **'
接口此功能的正确方法是什么?
答案 0 :(得分:2)
它不适用于numpy-arrays。您必须自己进行内存管理,例如:
%%cython
from libc.stdlib cimport free
def doit():
cdef int *ptr;
add_array(&ptr, 5)
print(ptr[4])
free(ptr) #memory management
尝试的区别:&arr_memview[0]
是指向整数数组的指针,但函数所需的是指向整数数组的指针的指针-即&ptr
。 / p>
您的功能存在的问题是,它的职责过多:
如果add_array
仅做第二部分,即
void add_array(int *io_array, int n) {
int i;
for(i = 0; i < n; i++) {
io_array[i] = i;
}
}
因此任何内存都可以初始化(还有未用malloc
分配的内存)。
但是,可以使用返回的指针ptr
创建一个numpy数组,这并不那么简单:
cimport numpy as np
import numpy as np
np.import_array() # needed to initialize numpy-data structures
cdef extern from "numpy/arrayobject.h":
void PyArray_ENABLEFLAGS(np.ndarray arr, int flags) #not include in the Cython default include
def doit():
cdef int *ptr;
add_array(&ptr, 5)
# create numpy-array from data:
cdef np.npy_intp dim = 5
cdef np.ndarray[np.int32_t, ndim=1] arr = np.PyArray_SimpleNewFromData(1, &dim, np.NPY_INT32, ptr)
# transfer ownership of the data to the numpy array:
PyArray_ENABLEFLAGS(arr, np.NPY_OWNDATA)
return arr
以下值得一提:
np.import_array()
。如果没有调用np.import_array()
,Here is an example会发生什么。PyArray_SimpleNewFromData
之后,数据本身不归最终的numpy数组所有,因此我们需要启用OWNDATA
标志,否则会发生内存泄漏。我想详细说明上面的第3点。 Numpy使用特殊功能为数据分配/释放内存-它是PyDataMem_FREE
,并使用系统的free
。因此,就您而言(在add_array
中使用系统的malloc / free),一切正常。 ({PyDataMem_FREE
不应与PyArray_free
混淆,就像我在较早版本的答案中所做的那样。PyArray_free
负责释放其他元素(数组本身,以及维/跨度数据,而不是数据存储器)see here,并且根据Python版本而有所不同。
一种更加灵活/安全的方法是使用SO-post所示的PyArray_SetBaseObject
。