c++ Klassen richtig einbinden

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
ponc
User
Beiträge: 5
Registriert: Sonntag 24. März 2013, 17:46

Hi,

das Thema kommt ja so oder ähnlich hier schon häufiger vor. Aber ich habe immer noch Probleme, eine dll richtig einzubinden.

Ich möchte (in Blender) mit ctypes ein C++ Code in Python einbinden, um bestimmte Berechnungen zu beschleunigen. Von C++ habe ich allerdings noch keinen blassen Schimmer, versuche mir das aber auf diesem Weg zu erarbeiten.

Ich nutze Win7, Visual Studio Express und Python 3.2 - alle in, auf oder für 64bit

Zum Erstellen der dll habe ich das Tutorial von MS genommen: http://msdn.microsoft.com/de-de/library ... 80%29.aspx

Wenn ich das richtig verstanden habe, müsste ich die Funktionen der dll in Python so einbinden können:

Code: Alles auswählen

import ctypes
path = "C:/Users/.../Release/probe4"
testlib = ctypes.CDLL(path)
x = testlib.Add(2,4)
print(x)
Das funktioniert aber nicht. Ich bekomme die Meldung "AttributeError: function 'Add' not found"

Irgendwo habe ich dann mit Googles Hilfe die folgende Zeile gefunden:

Code: Alles auswählen

#pragma comment(linker, "/EXPORT:MyFuncAdd=?Add@MyMathFuncs@MathFuncs@@SANNN@Z")
Jetzt kann ich zwar auf die Funktion mit "testlib.MyFuncAdd(2,4)" zugreifen, aber der zurückgegebene Wert ist immer derselbe. Gleich, welche Werte ich mitgebe.

Mit dem "DLL Export Viewer" habe ich mir die Namen meiner Funktionen ausgeben lassen. Im Falle der originalen Add Funktion sieht die dann so aus:
public: static double __cdecl MathFuncs::MyMathFuncs::Add(double,double)
Da weiss ich nicht, wie ich das ansprechen soll.

#pragma ... erzeugt mir immerhin den Eintrag "MyFuncAdd", der ja dann auch funktioniert, allerdings nicht 6 zurückgibt, sondern 2225864.


Kann mir da jemand weiterhelfen? Alles googeln bringt grad nichts mehr.

Vielen Dank,

ponc
BlackJack

@ponc: Ich denke `ctypes` ist für C++ nicht wirklich geeignet. Das ist für C ohne das ++. Dann musst Du mit `ctypes` die Funktionen auch ”deklarieren”, denn das die Funktion zwei C++-``double``-Werte entgegen nimmt und einen Wert von eben diesem Typ zurück gibt, kann `ctypes` sonst ja nicht wissen. Das übergibt sonst ohne Prüfung das was Du übergibst, in diesem Fall zwei ganze Zahlen und geht, wie C, von einem C-``int`` als Rückgabewert aus, wenn nichts anderes angegeben wurde.

Aber wie gesagt: Für C++ würde ich `ctypes` nicht verwenden.

Edit: Eventuell könntest Du auch einfach C statt C++ nehmen!?
ponc
User
Beiträge: 5
Registriert: Sonntag 24. März 2013, 17:46

@BlackJack: vielen Dank für deine Antwort.

Was wäre denn besser für C++ geeignet? Und kann ich nicht "extern "C" " nutzen, damit C++ nach Außen als C dargestellt wird? (Wie schon oben gesagt, ich bin noch blutiger Anfänger in C/C++)

Mit argtypes und restype funktioniert es jetzt:

Code: Alles auswählen

testlib.MyFuncAdd.restype = ctypes.c_double
testlib.MyFuncAdd.argtypes = [ctypes.c_double, ctypes.c_double]
Was mich noch stört, ist die Einbindung meiner Funktion in der Header Datei über das kryptische

Code: Alles auswählen

#pragma comment(linker, "/EXPORT:MyFuncAdd=?Add@MyMathFuncs@MathFuncs@@SANNN@Z")
Gibts da ne bessere Lösung?

Grüße,
ponc
BlackJack

@ponc: Dieses Pragma, was spezifisch für den Compiler ist, den Du verwendest, ist ja gerade dazu da dem ganzen nach aussen einen Namen zu geben der nach C aussieht. Mit ``extern C`` kann man das nur für Sachen machen, die auch tatsächlich C sind.

Da das „name mangling” von C++ nicht standardisiert ist, gibt es so etwas wie `ctypes` nicht für C++. Das bindet man üblicherweise mit Werkzeugen wie SIP, Boost::Python, oder Pyrex ein.
ponc
User
Beiträge: 5
Registriert: Sonntag 24. März 2013, 17:46

Vielen Dank für deine Hilfe.

Nach und nach erschließt es sich mir. Über C oder C++ werde ich nochmal nachdenken. Und die Funktionen kann ich erstmal über ihre Ordinalzahlen ansprechen.

Danke,
ponc
Faule Socke
User
Beiträge: 11
Registriert: Mittwoch 27. März 2013, 10:57

Hi,

du kannst extern "C" benutzen, um die Benennung der Symbole in den Binärdateien auf den C-Standard umzustellen. Allerdings ist damit AFAIK nicht gesichert, wie z.B. Funktionen von Klassen (also Methoden) heißen. Für kleine DLLs, in denen du kein OOP verwendest ist das kein Problem, da kannst du dann bequem mit ein paar Zeilen ctypes-Code auf das ganze Zugreifen, wenn du aber größere, objektorientierte Sachen machst, schau dir doch mal boost::python an.

Gruß Socke

P.S. Erster Beitrag :)
lunar

@Faule Socke: "extern C" hat keine Auswirkungen auf Methoden ("member functions") in Klassen. Nach ISO/IEC 14882:2003, Abschnitt 7.5, Absatz 4:
A C language linkage is ignored for the names of class members and the member function type of class member functions.
Man kann Methoden nicht an C exportieren.
Antworten