Seite 1 von 1

Python/C -> Python return in C-Variable umwandeln

Verfasst: Freitag 10. März 2006, 13:47
von windows97
Hallo!

Ich möchte mit der Python/C API Werte von einem Messgerät via Python einlesen und diese an eine C++-Applikation zurückgeben.
Die Ausgabe mit Python an sich klappt ohne Probs. Ebenso der Aufruf von Methoden ohne return -> void.
Leider kann ich den return von Python in C/C++ nicht korrekt umwandeln.
Hoffe jemand kann mir helfen.

Python Code:

Code: Alles auswählen

   def getVO(self):
	Answer = self.cmd('VO?')                ##get current Voltage
	if (Answer[-7] =='\r'):                 ##if V <10.00V
		Voltage = Answer[-5:-1]         ##filter Voltage out of Answer
	else:
		Voltage = Answer[-6:-1]         ##filter Voltage out of Answer
	float_Voltage = float(Voltage)
	print float_Voltage
	return float_Voltage                    ##return current Voltage
C++ Code:

Code: Alles auswählen

float powersupply::getVO ( void )
{
	PyObject *resp;
	float Vout;
	resp = PyObject_CallMethod( pInstance, "getVO", NULL);
	cout <<" Check: " << PyArg_ParseTuple(resp, "(f)", &Vout) << endl;
	cout <<" Vout:     " << Vout << endl;
	Py_DECREF(resp);
	return Vout;
}

Verfasst: Freitag 10. März 2006, 14:30
von Joghurt
Also erstmal willst du ja Vout ausgeben und nicht das Ergebnis von PyArg_ParseTuple. Also erst PyArg aufrufen und dann Vout ausgeben.

Aber abgesehen davon, warum nutzt du nicht einfach PyFloat_AsDouble? Die macht genau das, was du willst, nämlich einen double zurückgeben.

Verfasst: Freitag 10. März 2006, 14:57
von windows97
Hi!

Danke erstmal für die fixe Antwort!
Das es irgendwie so gehen musste war mit schon irgendwie klar!
Prob ist dann, wenn man nicht alle Funktionen im Kopf hat. :oops:
Jetzt klappt es auf jeden Fall! - Danke

Hier dann jetzt nochmal die geänderte Soucre:

C++ Code:

Code: Alles auswählen

double powersupply::getVO ( void )
{
	double  Vout;
	PyObject *response;
	response = PyObject_CallMethod( pInstance, "getVO", NULL );
	Vout = PyFloat_AsDouble( response );
	Py_DECREF( response );
	return Vout;
}

Verfasst: Freitag 10. März 2006, 15:11
von modelnine
Du behandelst keinerlei Exceptions die im Python-Code entstehen können, das weißt Du? Das prädestiniert Dich für core-dumps aller Art. ;-)

Verfasst: Freitag 10. März 2006, 15:44
von windows97
Was genau meinst du damit?
Unerwartete Daten in der Kommunikation mit dem Netzgerät werden in der cmd-Methode bei mir realisiert.
Oder meinst den Instanzenaufruf in C?

Verfasst: Freitag 10. März 2006, 18:53
von Joghurt
Und was ist, wenn Voltage nun "jcau2j" enthält, der float mit einer Exception fehlschlägt und PyFloat_AsDouble deshalb müll schreibt?

Verfasst: Freitag 10. März 2006, 19:26
von windows97
Mmh, okay! An dieser Stelle kann ich eigentlich nur sagen:

Code: Alles auswählen

self.cmd('VO?')
Gebe ich dem Netzgerät den Befehl mir die Output-Spannung zu liefern.
Dies wird auch getan! Auf jeden Fall während meiner etwa 2000 Versuche.
Sollte ich denn jetzt zusätzlich noch verfizieren, dass ich tatsächlich die Spannung zurückbekomme? :?:

Verfasst: Freitag 10. März 2006, 20:14
von modelnine
Darum gings bei mir zumindest nicht. Worum es geht: wenn die Python-Funktion die Du aus dem C++-Code aufrufst eine Exception schmeißt (weil irgendwas in der Funktion schiefgeht, kann ja durchaus sein dass Du eben mal keinen Spannungswert zurückkriegst oder float() meckert weil die Daten eben keins sind), dann gibt der Funktionsaufruf ein NULL zurück (also PyObject_CallMethod), und der Exception-State des Threads ist gesetzt.

Du probierst dann auf die Ausgabe (also NULL) ein PyFloat_AsDouble, was an sich funktionieren sollte, weil die *_AsBlah eine eigene Typprüfung machen (wobei ich nicht weiß ob sie auf NULL testen, würde ich aber einfach mal vermuten), was die *_ASBLAH nicht machen (es gibt auch PyFloat_ASDOUBLE), da das einfach nur Makros sind. Da auf jeden Fall ein NULL nicht in ein Float gewandelt werden kann gibts auch wieder NULL (also den Wert null) als Float zurück, und der exception-Status wird neu gesetzt.

Als nächstes probierst Du dann NULL zu DECREFfen, was spätestens jetzt einen Core-Dump produziert, weil nämlich DECREF auch nur ein Makro ist, was seine Eingabe nicht prüft.

Sprich: wenn irgendwas in Deinem Python-Programm nicht geht (und eben eine Exception geschmissen wird), bedeutet das, dass Deine powersupply::getVO einen Core-Dump provoziert.

Abhilfe schaffen dürfte einfach ein:

Code: Alles auswählen

    ...
    if( !( response = PyObject_CallMethod(pInstance,...) ) ) {
        // Fehlerbehandlung
        PyErr_Clear(); // Um den Exception-Status zu löschen, wichtig für gc des Traceback-Objekts.
        return 0;
    }
    ...
Lies mal die relevanten Passagen aus der Doku zum Python-C-API über Exception-Handling in C.

Verfasst: Freitag 10. März 2006, 23:09
von windows97
Okay, jetzt hab auch ichs gerallt. :roll:
Werd mir das Kapitel auf jeden Fall mal antun.
Danke!

Verfasst: Samstag 11. März 2006, 00:56
von Joghurt
modelnine hat geschrieben:Darum gings bei mir zumindest nicht. Worum es geht: wenn die Python-Funktion die Du aus dem C++-Code aufrufst eine Exception schmeißt (weil irgendwas in der Funktion schiefgeht, kann ja durchaus sein dass Du eben mal keinen Spannungswert zurückkriegst oder float() meckert weil die Daten eben keins sind)
Genau das meinte ich (auch).
float("fjafakjb") schmeißt eine ValueError Exception