代码之家  ›  专栏  ›  技术社区  ›  Woody1193 Nimmi Rashinika

指针和“存储临时Python引用的不安全C派生”

  •  11
  • Woody1193 Nimmi Rashinika  · 技术社区  · 9 年前

    我正在编写代码,将一个(可能)非常大的整数值存储到 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
    

    当我尝试编译代码时,在注释行出现错误,“存储临时Python引用的不安全C派生”。我的问题是:我在C中派生并存储了哪个临时Python引用,以及如何修复它?

    2 回复  |  直到 9 年前
        1
  •  12
  •   rll    9 年前

    问题是,在将数组赋值给 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)
    
        2
  •  8
  •   DavidW    9 年前

    @rll的答案在清理代码和“正确处理所有事情”(最重要的是 __dealloc__ 在问题中!)。

    导致错误的实际问题是您没有 cimport 预计起飞时间 malloc 。因此,Cython假设 锦葵属植物 是一个Python函数,返回要转换为 char* 。在文件的顶部,添加

    from libc.stdlib cimport malloc, free
    

    它会奏效的。或替代使用 PyMem_Malloc (cimport)就像@rll一样,这也会很好。