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

Woo*_*193 9 c python 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
Run Code Online (Sandbox Code Playgroud)

当我尝试编译代码时,我在注释行中收到错误"存储临时Python引用的不安全C派生".我的问题是:我在C中存储的临时Python参考和存储,以及如何修复它?

rll*_*rll 8

问题是在引擎盖下创建了一个临时变量来在分配之前保存数组,self.Array并且一旦该方法退出就不会有效.

请注意,文档建议:

用于在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)
Run Code Online (Sandbox Code Playgroud)


Dav*_*idW 6

@ rll的答案在清理代码和"正确完成所有事情"方面做得非常好(最重要的是__dealloc__在问题中缺少的内存释放!).

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

from libc.stdlib cimport malloc, free
Run Code Online (Sandbox Code Playgroud)

它会工作的.或者PyMem_Malloc像@rll一样使用(cimporting),这样也可以.