CTypes ungültige Speicherallokation
Verfasst: Sonntag 26. Juli 2020, 22:19
Hallo nochmal,
ich habe ein weiteres Problem mit CTypes und bin mir nicht mal sicher, ob ich beschreiben kann, was genau das Problem ist.
Meine Ausgangssituation ist folgende:
Ich habe eine .so in C zur Verfügung, wessen structs und Methoden ich in Python (in schöner Weise) zur Verfügung stellen will, und zwar mit CTypes. Wie in dem Thread schon mir erklärt wurde, sieht meine Struktur so aus, dass ich in Python zwei Klassen pro struct in C habe. Bspw. gibt es eine struct "vector" in C, dann habe ich eine Klasse "class LibVector(ctypes.Structure)" in Python, in welcher die Felder mittels _fields_ gesetzt werden. Genauso werden die C-Methoden dann in Python wie folgt erstellt, wobei get_func eine eigene Helperfunktion ist, welche nur die Funktion aus der Lib "holt" und dann die ".restype" und ".argtypes" Attribute setzt.
Nun habe ich eine weitere Klasse "class Vector()", welche diese Methoden nun zur Verfügung stellen soll und ein LibVector-Objekt wrappt. Grob sieht das Ganze nun so aus:
Nun habe ich ein Beispielprogramm, welches prinzipiell eine Matrix A und einen Vektor b erzeugt, und dann ein Gleichungssystem lösen soll, sprich Ax = b nach x auflösen soll.
Wenn ich nun nur die ganzen LibXyz-Klassen nutze, funktioniert alles ohne Probleme, ist aber etwas unschön (der Nutzer muss sich etwas mit CTypes auseinandersetzen, das will ich ja eben mit der zweiten Klasse vermeiden). Wenn ich nun aber meine "besseren" Klasse nutze, läuft an folgender Stelle etwas schief: Um Ax = b lösen zu können, muss x mittels Vector.new(dim) erzeugt und dann in der C-Methode befüllt werden. Allerdings sollte durch das .new() ein leerer Vektor erzeugt werden (sprich nur 0en), allerdings scheinen einige Elemente sogar nichtmal gültige doubles zu sein, sodass C daraus "nan"s macht. Dies hat zur Folge, dass die ganze Rechnung nicht mehr funktioniert.
Das Alles wäre gar nicht so ein großes Problem, wenn dieser Fehler nicht so sporadisch auftreten würde. Bspw. bei niedrigeren Dimensionen habe ich den Fehler nicht. Die Dimension bekomme ich von einem Feld einer anderen Klasse, wenn ich dieses Feld vorher in einer Variable speichere, bekomme ich auch keinen Fehler mehr.
Die Dimension bekomme ich über "d._as_parameter_.contents.tri". Dafür habe ich __get_attr__ überschrieben, sodass "d.tri" das gleiche tut. Mit ersterem funktioniert mein Programm, mit letzterem wieder nicht (??).
Mir ist bewusst, dass ich noch nicht viel Code bereitgestellt habe. Ich wollte nur zunächst sichergehen, dass ich nichts fundamentales falsch verstanden habe, was Projektion von C structs in Python anbelangt. Es scheint mir ein Speicherallokationsproblem zu sein, aber ich kann weder sagen ob in C oder in Python (wobei es wohl Python ist), und sobald ich sehe, dass es mit Variablen und anderen Versuchen wieder funktioniert und dann wieder nicht, war mein Verständnis für Python auch langsam am Ende.
Ich bin jedem dankbar, der sich die Mühe macht, das nachzuvollziehen, und freue mich über jeden Tipp in die richtige Richtung, wo ich noch nachschauen kann. Mir scheint das momentan recht willkürlich, obwohl es ja deterministisch ist (wenns mit eine Code geht / nicht geht, dann ist das immer so, egal wann ich das wie oft ausführe). Falls etwas unklar sein sollte, versuche ich das natürlich gern zu erklären.
Gruß Plexian
ich habe ein weiteres Problem mit CTypes und bin mir nicht mal sicher, ob ich beschreiben kann, was genau das Problem ist.
Meine Ausgangssituation ist folgende:
Ich habe eine .so in C zur Verfügung, wessen structs und Methoden ich in Python (in schöner Weise) zur Verfügung stellen will, und zwar mit CTypes. Wie in dem Thread schon mir erklärt wurde, sieht meine Struktur so aus, dass ich in Python zwei Klassen pro struct in C habe. Bspw. gibt es eine struct "vector" in C, dann habe ich eine Klasse "class LibVector(ctypes.Structure)" in Python, in welcher die Felder mittels _fields_ gesetzt werden. Genauso werden die C-Methoden dann in Python wie folgt erstellt, wobei get_func eine eigene Helperfunktion ist, welche nur die Funktion aus der Lib "holt" und dann die ".restype" und ".argtypes" Attribute setzt.
Code: Alles auswählen
# libvector.py
new_avector = get_func('new_avector', PTR(CStructAVector), [c_uint])
fill_avector = get_func('fill_avector', None, [PTR(CStructAVector), c_double])
Code: Alles auswählen
#vector.py
class Vector():
def __init__(self, cobj):
assert isinstance(cobj, POINTER(libvector.LibVector))
self._as_parameter_ = cobj
@classmethod
def new(cls, dim: int):
return cls(libvector.new_vector(dim))
def fill(self, value):
libvector.fill_vector(self, c_double(value))
Wenn ich nun nur die ganzen LibXyz-Klassen nutze, funktioniert alles ohne Probleme, ist aber etwas unschön (der Nutzer muss sich etwas mit CTypes auseinandersetzen, das will ich ja eben mit der zweiten Klasse vermeiden). Wenn ich nun aber meine "besseren" Klasse nutze, läuft an folgender Stelle etwas schief: Um Ax = b lösen zu können, muss x mittels Vector.new(dim) erzeugt und dann in der C-Methode befüllt werden. Allerdings sollte durch das .new() ein leerer Vektor erzeugt werden (sprich nur 0en), allerdings scheinen einige Elemente sogar nichtmal gültige doubles zu sein, sodass C daraus "nan"s macht. Dies hat zur Folge, dass die ganze Rechnung nicht mehr funktioniert.
Das Alles wäre gar nicht so ein großes Problem, wenn dieser Fehler nicht so sporadisch auftreten würde. Bspw. bei niedrigeren Dimensionen habe ich den Fehler nicht. Die Dimension bekomme ich von einem Feld einer anderen Klasse, wenn ich dieses Feld vorher in einer Variable speichere, bekomme ich auch keinen Fehler mehr.
Die Dimension bekomme ich über "d._as_parameter_.contents.tri". Dafür habe ich __get_attr__ überschrieben, sodass "d.tri" das gleiche tut. Mit ersterem funktioniert mein Programm, mit letzterem wieder nicht (??).
Mir ist bewusst, dass ich noch nicht viel Code bereitgestellt habe. Ich wollte nur zunächst sichergehen, dass ich nichts fundamentales falsch verstanden habe, was Projektion von C structs in Python anbelangt. Es scheint mir ein Speicherallokationsproblem zu sein, aber ich kann weder sagen ob in C oder in Python (wobei es wohl Python ist), und sobald ich sehe, dass es mit Variablen und anderen Versuchen wieder funktioniert und dann wieder nicht, war mein Verständnis für Python auch langsam am Ende.
Ich bin jedem dankbar, der sich die Mühe macht, das nachzuvollziehen, und freue mich über jeden Tipp in die richtige Richtung, wo ich noch nachschauen kann. Mir scheint das momentan recht willkürlich, obwohl es ja deterministisch ist (wenns mit eine Code geht / nicht geht, dann ist das immer so, egal wann ich das wie oft ausführe). Falls etwas unklar sein sollte, versuche ich das natürlich gern zu erklären.
Gruß Plexian