我想在 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;
}
和函数原型(prototype):
#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 **'
连接此功能的正确方法是什么?
最佳答案
它不能与 numpy 数组开箱即用。您必须自己进行内存管理,例如:
%%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
是。
你的函数的问题是,它有太多的职责:
- 它分配内存
- 它初始化内存
如果 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()
需要能够使用 numpy 的所有功能。 Here is an example如果未调用np.import_array()
会发生什么。 - 在
PyArray_SimpleNewFromData
之后,数据本身不属于生成的 numpy 数组,因此我们需要启用OWNDATA
标志,否则会发生内存泄漏。 - 生成的 numpy 数组可以负责释放数据并不明显。例如,可以使用 Python's memory allocator 而不是使用 malloc/free .
我想详细说明上面的第 3 点。 Numpy 使用一个特殊的函数来为数据分配/释放内存——它是 PyDataMem_FREE
并为其使用系统的免费
。因此,在您的情况下(在 add_array
中使用系统的 malloc/free)一切正常。 (PyDataMem_FREE
不应与 PyArray_free
混淆,正如我在早期版本的答案中所做的那样。PyArray_free
负责释放其他元素(数组本身和维度/跨越 numpy 数组的数据,而不是数据内存,see here 并且根据 Python 版本而有所不同)。
一种更灵活/安全的方法是使用 PyArray_SetBaseObject
,如 SO-post 所示.
关于c - 在 Cython 中通过双指针从 C 函数传递数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51546710/