Ich schreibe eine C-Erweiterung zu meinem Python-Programm für Geschwindigkeitszwecke, und renne in ein sehr merkwürdiges Verhalten, indem ich versuche, ein 3-dimensionales numpiges Array zu übergeben. Es funktioniert mit einem 2-dimensionalen Array, aber ich bin mir sicher, dass ich etwas mit den Zeigern vermassle, die versuchen, es mit der 3. Dimension zu arbeiten. Aber hier ist der komische Teil. Wenn ich nur ein 3-D-Array übergebe, stürzt es mit einem Busfehler ab. Wenn ich (in Python) meine Variable zuerst als ein 2D-Array erzeuge und sie dann mit einem 3D-Array überschreibe, funktioniert es einwandfrei . Wenn die Variable zuerst ein leeres Array und dann ein 3D-Array ist, stürzt sie mit einem Seg Fehler ab. Wie kann das passieren?3-dimensionales numpy Array an C
Kann mir auch jemand helfen, ein 3D-Array zu bekommen? Oder sollte ich einfach aufgeben und ein 2D-Array übergeben und es selbst umformen?
Hier ist mein C-Code:
static PyObject* func(PyObject* self, PyObject* args) {
PyObject *list2_obj;
PyObject *list3_obj;
if (!PyArg_ParseTuple(args, "OO", &list2_obj, &list3_obj))
return NULL;
double **list2;
double ***list3;
//Create C arrays from numpy objects:
int typenum = NPY_DOUBLE;
PyArray_Descr *descr;
descr = PyArray_DescrFromType(typenum);
npy_intp dims[3];
if (PyArray_AsCArray(&list2_obj, (void **)&list2, dims, 2, descr) < 0 || PyArray_AsCArray(&list3_obj, (void ***)&list3, dims, 3, descr) < 0) {
PyErr_SetString(PyExc_TypeError, "error converting to c array");
return NULL;
}
printf("2D: %f, 3D: %f.\n", list2[3][1], list3[1][0][2]);
}
Und hier ist mein Python-Code, der die obige Funktion aufruft:
import cmod, numpy
l2 = numpy.array([[1.0,2.0,3.0], [4.0,5.0,6.0], [7.0,8.0,9.0], [3.0, 5.0, 0.0]])
l3 = numpy.array([[2,7, 1], [6, 3, 9], [1, 10, 13], [4, 2, 6]]) # Line A
l3 = numpy.array([]) # Line B
l3 = numpy.array([[[2,7, 1, 11], [6, 3, 9, 12]],
[[1, 10, 13, 15], [4, 2, 6, 2]]])
cmod.func(l2, l3)
Also, wenn ich beide Linie Kommentar aus A und B, es mit einem Absturz Busfehler Wenn Zeile A vorhanden ist, Zeile B jedoch auskommentiert ist, wird sie fehlerfrei ausgeführt. Wenn Zeile B vorhanden ist, aber Zeile A auskommentiert ist, werden die richtigen Zahlen und dann die Seg-Fehler ausgegeben. Wenn beide Zeilen vorhanden sind, werden auch die richtigen Nummern und dann Seg-Fehler ausgegeben. Was zum Teufel geht hier vor?
EDIT: Ok. Beeindruckend. Also benutzte ich int
in Python, aber nannte sie double
in C. Und das funktionierte gut mit 1D- und 2D-Arrays. Aber nicht 3D. Also habe ich die Python-Definition von l3 geändert, um Floats zu sein, und jetzt funktioniert alles fantastisch (Vielen Dank Bi Rico).
Aber jetzt, seltsamer Verhalten mit Linien A & B! Wenn nun beide Zeilen auskommentiert sind, funktioniert das Programm. Wenn Zeile B vorhanden ist, aber A auskommentiert ist, funktioniert es, und dito, wenn beide unkommentiert sind. Aber wenn Zeile A vorhanden ist und B auskommentiert ist, bekomme ich wieder diesen fantastischen Busfehler. Ich möchte diese in Zukunft wirklich vermeiden, also hat irgendjemand irgendeine Ahnung, warum die Deklaration einer Python-Variablen diese Art von Auswirkungen haben kann?
EDIT 2: Nun, so verrückt, wie diese Fehler sind, sind sie alle aufgrund der 3-dimensionalen numpy Array, die ich weitergeben. Wenn ich nur in 1- oder 2-D-Arrays übergeben, verhält es sich wie erwartet und Manipulation der anderen Python-Variablen tut nichts. Das führt mich zu der Annahme, dass das Problem irgendwo in Pythons Referenzzählung liegt. Im C-Code wird die Referenzzahl mehr als für die 3-D-Arrays verringert, und wenn diese Funktion zurückkehrt, versucht Python, Objekte zu bereinigen und versucht, einen NULL-Zeiger zu löschen. Das ist nur meine Vermutung, und ich habe versucht, Py_INCREF();
alles, was ich denken konnte, ohne Erfolg. Ich denke, ich werde nur einen 2D-Array verwenden und Umformen es in C.
Sind Sie sicher, dass '(void **)' richtig ist, sollte nicht nur Sie passieren in a '(void *)'? – seberg
Mein C saugt aber ... Ist Ihr Ausdruck im 'if' nicht kurzgeschlossen, wenn der erste Aufruf von' PyArray_AsCArray' erfolgreich ist? Es kann sehr gut sein, dass der zweite Aufruf, d. H. Der für "list3", niemals gemacht wird. – Jaime
@seberg Ich bin nicht sicher, dass '(void **)' korrekt ist, aber '(void *)' verursacht einen Busfehler. @Jaime Nein, diese Funktion gibt nur dann negative Werte zurück, wenn sie fehlschlägt, höchstwahrscheinlich, wenn das von ihr aufgerufene malloc fehlschlägt. – DaveTheScientist