2015-09-03 12 views
6

Ich schrieb Code, um einen (potentiell) sehr großen Integer-Wert in ein Array von chars zu speichern, auf das von einem Zeiger verwiesen wird. Mein Code sieht wie folgt aus:Zeiger und "Speichern unsichere C-Ableitung der temporären Python-Referenz"

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 

Wenn ich den Code versucht, kompilieren, ich die Fehlermeldung anzeigt, „Speichern von unsicheren C-Derivat von temporären Python Referenz“ an der Kommentarzeile. Meine Frage ist: Welche temporäre Python-Referenz erhalte ich in C und speichere sie und wie behebe ich sie?

Antwort

3

Das Problem ist, dass unter der Haube eine temporäre Variable erstellt wird, um das Array vor der Zuweisung an self.Array zu halten, und es wird nicht gültig sein, sobald die Methode beendet wird.

beachten, dass die documentation rät:

die C-API-Funktionen für den Speicher auf dem Python heap Zuteilen werden über die Low-Level-C-Funktionen im allgemeinen bevorzugt, das oben als Speicher bieten sie tatsächlich in Python entfielen internes Speicherverwaltungssystem. Sie haben auch spezielle Optimierungen für kleinere Speicherblöcke, was ihre Zuweisung beschleunigt, indem kostspielige Betriebssystemaufrufe vermieden werden.

Dementsprechend können Sie wie unten schreiben, die diesen Anwendungsfall zu behandeln scheint, als gedacht:

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 Antwort den Code für die Säuberung und „tut alles richtig“ einen ziemlich guten Job tut (am wichtigsten ist die Freigabe von Speicher, die in der Frage __dealloc__ fehlte!).

Das eigentliche Problem, das den Fehler verursacht, ist, dass Sie cimport ed malloc nicht haben. Aus diesem Grund geht Cython davon aus, dass malloc eine Python-Funktion ist, die ein Python-Objekt zurückgibt, das in eine char* umgewandelt werden soll. Fügen Sie oben in der Datei

from libc.stdlib cimport malloc, free 

hinzu und es wird funktionieren. Oder alternativ PyMem_Malloc (cimporting it) als @ rll tut, und das wird auch gut funktionieren.

Verwandte Themen