【问题标题】:Pointers and "Storing unsafe C derivative of temporary Python reference"指针和“存储临时 Python 引用的不安全 C 派生”
【发布时间】:2015-11-29 01:39:55
【问题描述】:

我正在编写代码以将(可能)非常大的整数值存储到由指针引用的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 引用,我该如何修复它?

【问题讨论】:

    标签: python c pointers cython python-extensions


    【解决方案1】:

    问题在于,在分配给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】:

      @rll 的回答在清理代码和“正确执行所有操作”方面做得非常好(最重要的是问题中__dealloc__ 缺少的内存释放!)。

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

      from libc.stdlib cimport malloc, free
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-17
        • 2015-05-21
        • 2018-07-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多