Ctypes

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
Neutral
User
Beiträge: 6
Registriert: Donnerstag 9. Oktober 2008, 09:03

Guten Tag,
ich habe ein Problem bei der Benutzung von Ctypes, im speziellen von double und float variablen. Ich versuche momentan in meinem Pythonprogramm eine C Funktion aufzurufen, was auch mit int Werten klappt, aber bei double scheitert.
Da ich nicht genau weiß, wie ich es formulieren soll, gebe ich einfach mal den Code an.

Funktionierender Code:
C++ Code
extern "C" __declspec(dllexport) int addition (int zahl1 ,int zahl2)
{
int res = zahl1 + zahl2;
return res;
}
Code in Python
def test(wert1, wert2):
Quelle = ctypes.cdll.LoadLibrary("C:\\temp\\pythonfkt.dll")
res = Quelle.addition(wert1,wert2)
print res

test(2,6)
Dieses kleine Programm klappt aber folgendes nicht:
C++
extern "C" __declspec(dllexport) double multi (double wert1, double wert2)
{
double res = wert1 * wert2;
return res;
}
Python
def test2(wert1, wert2):
Quelle = ctypes.cdll.LoadLibrary("C:\\temp\\pythonfkt.dll")
zahl = Quelle.multi(wert1,wert2)
print zahl

test2(3.3,4.5)
Kann mir vielleicht jemand weiter helfen?

Gruß, der Praktikant
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Du musst die Werte erst in c_double umwandeln.
MfG
HWK
Neutral
User
Beiträge: 6
Registriert: Donnerstag 9. Oktober 2008, 09:03

Habe es mit c_double versucht, jedoch bekomme ich nicht das gewünschte Ergebnis.

Ist der Code so richtig?

Als Ausgabe erhalte ich nämlich einfach nur "c_double(2226876.0)"

Code: Alles auswählen

def test2(wert1, wert2):
	wert1 = ctypes.c_double(wert1)
	wert2 = ctypes.c_double(wert2)
	zahl = Quelle.multi(wert1,wert2)
	print zahl

test2(3.3,4.5)
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Ja, das ist richtig. Der Python-Float befindet sich im value-Attribut des Ergebnisses. Alternativ kannst Du auch restype und argtypes verwenden.
MfG
HWK
Neutral
User
Beiträge: 6
Registriert: Donnerstag 9. Oktober 2008, 09:03

Als Ausgabe erhalte ich aber jedoch, wie oben beschrieben, "c_double(2226876.0)".

Wie bekomme ich nun das richtige Ergebnis von 3,3 * 4,4?
Ich möchte halt einfach nur das Ergebnis, in diesem Falle 14,85, in der Variable zahl stehen haben.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Code: Alles auswählen

import ctypes
double_mul = ctypes.WinDLL('double_mul').double_mul
double_mul.argtypes = (ctypes.c_double, ctypes.c_double)
double_mul.restype = ctypes.c_double
print double_mul(3.3, 4.5)
Wichtig ist restype, sonst wird ein int zurückgeliefert.
MfG
HWK
Neutral
User
Beiträge: 6
Registriert: Donnerstag 9. Oktober 2008, 09:03

Vielen Dank für die Hilfe, es klappt nun.
Habe mich gestern ziemlich dämlich angestellt :oops:
und zum Beispiel das ctypes vor dem c_double vergessen und wundere mich warum nichts klappt und andere kleine Fehler.
Es läuft nun aber endlich, vielen dank :wink:
zotti
User
Beiträge: 4
Registriert: Dienstag 7. Juli 2009, 10:43

Hi!

Habe ebenfalls ein Problem mit C++ und Python.

Ich habe eine Funktion in C++ die ein double-Array zurückgibt.

Code: Alles auswählen

extern "C" __declspec(dllexport)double *rotp (double a double b, double ....)
	{	
		static double ret[3] = {0.0,0.0,0.0};
                ...
                ...
                ret[0]=...
                ret[1]=...
                ret[2]=...
                ...
                return ret;
}
Dieses Funktion möchte ich nun in Python aufrufen und das Array auslesen.

Code: Alles auswählen

quelle =  ctypes.cdll.LoadLibrary("C:\\PythonTest\\pythondll.dll")
quelle.rotp.restype = ctypes.c_double * 3

def rotpC(a, b, ...):
    value = quelle.rotp(ctypes.c_double(a),ctypes.c_double(b),...)
    return value

test=rotpC(90,0,0,1,0,0,0,99,0,0)
for i in test: print 'rotpC  ',i
Nur bekomme ich falsche Ergebnisse. Die C-Funktion habe ich seperat in C getestet, in dem double-Array befinden sich die richtigen Werte.
Nur habe ich keine Ahnung warum in Python falsche Werte zurückkommen, z.B.:
rotpC 1.79451049856e-168
rotpC 5.6538500995e-317
rotpC 1.79451074428e-168
also quasi alles 0

Hoffe mir kann jmd helfen. Bin nicht so erfahren in beiden Gebieten.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Die C++-Funktion liefert doch einen Pointer zurück, also wahrscheinlich:

Code: Alles auswählen

quelle.rotp.restype = ctypes.pointer(ctypes.c_double * 3)
MfG
HWK
zotti
User
Beiträge: 4
Registriert: Dienstag 7. Juli 2009, 10:43

Danke für deine Hilfe.
Habe es so versucht, jedoch bekomme ich folgende Fehlermeldung

Bild

Habe danach gegoogelt bin aber nicht wirklich drauß schlau geworden.
Laut Googlesuche wäre der Typ nach "ctypes.pointer" falsch, aber das kann ja nicht sein...denke ich.

Weiß jmd vll weiter?
BlackJack

@zotti: Du musst `POINTER()` statt `pointer()` verwenden. Ersteres erstellt einen Typ, letzteres ein Exemplar von einem Zeiger auf ein anderes Exemplar.
zotti
User
Beiträge: 4
Registriert: Dienstag 7. Juli 2009, 10:43

Danke für die Antwort.

Bekomme keiner Fehlermeldung mehr, jedoch auch nicht die gewünschte Ausgabe.
Sondern nur:
<ctypes.LP_c_double_Array_3 object at 0x009EC800>
.

Dies passiert mit einem normlen "print result"
und mit einer Schleife wie hier "for i in result: print i".
"print len(result)" sagt mir auch, dass dieser Objekttyp keine Länge hat... vll bekomm ich deswegen auch mittels Schleife ne endlose Ausgabe.

Hätte nicht gedacht dass es so kompliziert es nen Array aus C auszugeben. Oder der Fehler sitzt wie so oft vorm Rechner;)

Noch jmd ne Idee?
BlackJack

@zotti: Das ist genau wie in C, da kann man auch bei einem Zeiger per Index auf beliebige, auch nichtexistente Elemente zugreifen. Den Index direkt beim Zeiger zu verwenden ist aber sowieso falsch, weil das ja sozusagen ein Array von drei-elementigen Arrays wäre. Man muss zuerst den Zeiger dereferenzieren und dann hat man das Array, das in Python netterweise sogar seine Länge kennt. In C wäre das nicht der Fall. Um's nochmal in C auszudrücken: Du versuchst ``foo``, wo Du eigentlich ``*foo`` haben möchtest. Und in Python:

Code: Alles auswählen

In [36]: b
Out[36]: <ctypes.LP_c_double_Array_3 object at 0xb7806fa4>

In [37]: b.contents
Out[37]: <__main__.c_double_Array_3 object at 0xb77bb6a4>

In [38]: len(b.contents)
Out[38]: 3

In [39]: list(b.contents)
Out[39]: [0.0, 0.0, 0.0]

In [40]: for x in b.contents:
   ....:     print x
   ....:
0.0
0.0
0.0
zotti
User
Beiträge: 4
Registriert: Dienstag 7. Juli 2009, 10:43

Vielen Dank BackJack, es funktioniert nun!

Und die Erklärung ist auch gut verständlich, mit guten Beispielen.

Danke nochmals an alle, die mir geholfen haben :)
Antworten