Seite 1 von 1

Ctypes

Verfasst: Montag 29. Juni 2009, 11:41
von Neutral
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

Verfasst: Montag 29. Juni 2009, 12:13
von HWK
Du musst die Werte erst in c_double umwandeln.
MfG
HWK

Verfasst: Montag 29. Juni 2009, 12:28
von Neutral
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)

Verfasst: Montag 29. Juni 2009, 12:35
von HWK
Ja, das ist richtig. Der Python-Float befindet sich im value-Attribut des Ergebnisses. Alternativ kannst Du auch restype und argtypes verwenden.
MfG
HWK

Verfasst: Montag 29. Juni 2009, 12:56
von Neutral
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.

Verfasst: Montag 29. Juni 2009, 13:18
von HWK

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

Verfasst: Dienstag 30. Juni 2009, 07:56
von Neutral
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:

Verfasst: Dienstag 7. Juli 2009, 10:53
von zotti
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.

Verfasst: Dienstag 7. Juli 2009, 13:17
von HWK
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

Verfasst: Dienstag 7. Juli 2009, 13:49
von zotti
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?

Verfasst: Dienstag 7. Juli 2009, 18:28
von BlackJack
@zotti: Du musst `POINTER()` statt `pointer()` verwenden. Ersteres erstellt einen Typ, letzteres ein Exemplar von einem Zeiger auf ein anderes Exemplar.

Verfasst: Mittwoch 8. Juli 2009, 08:18
von zotti
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?

Verfasst: Mittwoch 8. Juli 2009, 08:34
von 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

Verfasst: Mittwoch 8. Juli 2009, 08:47
von zotti
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 :)