9

我有一个在常规 Python 中创建的浮点值数组,我想将其传递给一个面向底层 C 函数的 cython 函数。C 函数要求将数组作为浮动指针传递,如下所示:

void setOverlays(const float * verts);

cython 包装器看起来像这样:

def set_overlays(verts):
    setOverlays(verts)

如何将 verts 制作成 cython 数组?我认为这可能有效:

cdef float * cVerts = [v for v in verts]

但不幸的是,生成的值是一个 Python 对象,在这种情况下自动转换不起作用。

ctypes 中的等效表达式(有效)是:

cVerts = (c_float * len(verts))()
for i in range(len(verts)):
    cVerts[i] = verts[i]
setOverlays(cast(byteref(cVerts), POINTER(c_float)))

我正在尝试实现相同的目标,但是在 cython

提前致谢!

4

5 回答 5

5

我相信您可以通过迭代 python 浮点列表并将它们放入 C 数组中来做到这一点。

cimport cython
from libc.stdlib cimport malloc, free

cdef:
    float * cfloats
    int i

cfloats = <float *> malloc(len(pyfloats)*cython.sizeof(float))
if cfloats is NULL:
  raise MemoryError()
for i in xrange(len(pyfloats)):
  cfloats[i] = pyfloats[i]
setOverlays(cfloats)
free(cfloats)
于 2012-07-27T14:41:30.887 回答
4

接受的答案是错误的并导致分段错误,因为float *从未分配过内存。

@JAB 的答案显示了要走的路,但我想详细说明。

传递一个数组:

问题是如何将 python 数组转换为 c 样式的数组。Python array(来自array模块)是连续内存的包装器,因此无需复制内存 - 我们只需将指针传递给 c 函数:

from cpython cimport array
import array

def set_overlays(array.array verts):
    setOverlays(verts.data.as_floats)

使用array模块比numpy因为它是标准库的一部分要好 - 不需要安装一些东西。这个解决方案简短而好,但有一个问题:有人可以将它与 an 一起使用int-array并且不会出现错误 - 内存只是被重新解释。有时这是一个人想要的,但大多数时候情况并非如此。

为了确保传递的数组对象具有正确的数据类型,可以使用内存视图:

from cpython cimport array #still needed

def set_overlays_memview(float[::1] verts):
    setOverlays(&verts[0])

[::1] 确保内存视图环绕连续内存。但是,如果内存视图中没有元素,则此代码存在问题,因为 out-of-bounds-access verts[0]。处理它的正确方法取决于功能setOverlays,而不是此答案的一部分。

传递一个列表:

如果我们必须将 python 列表传递给 c 函数,我们必须将值复制到连续内存中。最好使用以下功能array- 无需重新发明轮子:

from cpython cimport array
import array

def set_overlays_list(list verts):
    cdef array.array a =  array.array('f', verts)
    setOverlays(a.data.as_floats) #we already know they are floats
于 2017-02-06T21:42:40.513 回答
3

查看http://docs.cython.org/src/userguide/memoryviews.html。看起来它还提供了有关如何利用 Python 的内置array模块以及numpy.

于 2012-07-27T14:41:02.273 回答
-1

这是我用来准备数组以传递给 Cython 或带有 SWIG 的 C/CPP。

import numpy as np    
def make_c_array(a):
    """
    Take an input numpy array and convert to being ready for use in C.
    """
    b = []
    for i in range(len(a)):
        b.append(a[i])
    a = np.array(b,dtype=np.dtype('d'),order='C')
    return a
于 2016-09-14T08:38:49.227 回答
-2

我找到了 Cython 的特定方式:

cdef float* cVerts = []
    for i in xrange(len(verts)):
        cVerts[i] = verts[i]
setOverlays(cVerts)

有趣的是,上述两种解决方案都被 cython 编译器拒绝了。

于 2012-08-06T02:24:15.200 回答