Указатели и «Хранение небезопасной производной C от временной ссылки на Python»

Я писал код для хранения (потенциально) очень большого целочисленного значения в массив 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 

Когда я попытался скомпилировать код, я получил сообщение об ошибке «Хранение небезопасной производной C от временной ссылки Python» в комментариях. Мой вопрос таков: какую временную ссылку на Python я получаю на C и храня, и как ее исправить?

2 Solutions collect form web for “Указатели и «Хранение небезопасной производной C от временной ссылки на Python»”

Проблема заключается в том, что под капотом создается временная переменная для хранения массива до назначения для self.Array и он не будет действителен после выхода метода.

Обратите внимание, что в документации рекомендуется:

функции C-API для выделения памяти в куче Python обычно предпочтительнее описанных выше низкоуровневых 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) 

Ответ @ rll делает довольно хорошую работу по очистке кода и «все делает правильно» (самое главное, освобождение памяти, которое отсутствовало в __dealloc__ в вопросе!).

Фактическая проблема, вызывающая ошибку, заключается в том, что вы не cimport malloc cimport . Из-за этого Cython предполагает, что malloc – это функция Python, возвращающая объект Python, который вы хотите передать в char* . В верхней части файла добавьте

 from libc.stdlib cimport malloc, free 

и это сработает. Или, альтернативно, используйте PyMem_Malloc (cimporting it), как это делает @rll, и это тоже сработает.

  • Как работать с uint8_t на Python Extension?
  • Что такое PyObject в Python?
  • компилировать libdnet для python 2.7
  • Интеграция C и Python: ValueError: функции модуля не могут устанавливать METH_CLASS или METH_STATIC
  • почему я не смог построить sqlite3 при сборке python?
  • Могу ли я использовать скомпилированные Python-файлы MinGW вместе с скомпилированными Visual C ++?
  • Правильная циклическая сборка мусора в модулях расширения
  • Запуск Cython в Windows x64 - фатальная ошибка C1083: невозможно открыть файл include: basetsd.h: нет такого файла или каталога
  • Python - лучший язык программирования в мире.