指针和"存储临时Python参考的不安全C衍生物"

时间:2015-09-03 09:31:55

标签: python c pointers cython python-extensions

我正在编写代码以将(可能)非常大的整数值存储到由指针引用的chars数组中。我的代码如下所示:

cdef class Variable:

    cdef unsigned int Length
    cdef char * Array

    def __cinit__(self, var, length):
        self.Length = length
        self.Array = <char *>malloc(self.Length * sizeof(char))    # Error
        for i in range(self.Length):
            self.Array[i] = <char>(var >> (8 * i))

    def __dealloc__(self):
        self.Array = NULL

当我尝试编译代码时,我收到错误,&#34;存储临时Python引用的不安全C衍生物&#34;在评论行。我的问题是:我在C中存储的临时Python参考和存储,以及如何修复它?

2 个答案:

答案 0 :(得分:6)

问题在于,在分配给self.Array之前,正在创建一个临时变量来保存数组,并且一旦该方法退出,它就无效。

请注意documentation建议:

  

用于在Python堆上分配内存的C-API函数通常比上面的低级C函数更受欢迎,因为它们提供的内存实际上是在Python的内部内存管理系统中考虑的。它们还对较小的内存块进行了特殊优化,通过避免代价高昂的操作系统调用来加速分配。

因此,您可以编写如下,这似乎按预期处理此用例:

from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free

cdef class Variable:

    cdef unsigned int Length
    cdef char * Array

    def __cinit__(self, var,size_t length):
        self.Length = length
        self.Array = <char *>PyMem_Malloc(length * sizeof(char))
        #as in docs, a good practice
        if not self.Array:
            raise MemoryError()

        for i in range(self.Length):
            self.Array[i] = <char>(var >> (8 * i))

    def __dealloc__(self):
        PyMem_Free(self.Array)

答案 1 :(得分:6)

@ rll的答案在清理代码和“正确执行所有操作”方面做得非常好(最重要的是在问题__dealloc__中遗漏了内存的重新分配!)。

导致错误的实际问题是您没有cimport编辑malloc。因此,Cython假定malloc是一个Python函数,返回一个要转换为char*的Python对象。在文件顶部,添加

from libc.stdlib cimport malloc, free

它会起作用。或者使用PyMem_Malloc(cimporting)作为@rll,这也可以正常工作。