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

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
windows97
User
Beiträge: 24
Registriert: Freitag 10. März 2006, 13:34

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;
}
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

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.
Benutzeravatar
windows97
User
Beiträge: 24
Registriert: Freitag 10. März 2006, 13:34

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;
}
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

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. ;-)
--- Heiko.
Benutzeravatar
windows97
User
Beiträge: 24
Registriert: Freitag 10. März 2006, 13:34

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?
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Und was ist, wenn Voltage nun "jcau2j" enthält, der float mit einer Exception fehlschlägt und PyFloat_AsDouble deshalb müll schreibt?
Benutzeravatar
windows97
User
Beiträge: 24
Registriert: Freitag 10. März 2006, 13:34

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? :?:
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

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.
--- Heiko.
Benutzeravatar
windows97
User
Beiträge: 24
Registriert: Freitag 10. März 2006, 13:34

Okay, jetzt hab auch ichs gerallt. :roll:
Werd mir das Kapitel auf jeden Fall mal antun.
Danke!
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

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
Antworten