Frage

Ich bin nur mit ctypes getting started und möchte eine C ++ Klasse verwenden, die ich in einer DLL-Datei in Python exportiert habe mit ctypes. So können meine C ++ Code sagen etwas wie folgt aussieht:

class MyClass {
  public:
    int test();
...

Ich würde wissen, eine DLL-Datei erstellen, die diese Klasse enthält, und dann die DLL-Datei in Python mit ctypes laden. Nun, wie würde ich ein Objekt vom Typ MyClass erstellen und seine Testfunktion aufrufen? Ist das überhaupt möglich mit ctypes? Alternativ würde ich mit SWIG oder Boost.Python betrachtet aber ctypes scheint, wie die einfachste Möglichkeit für kleine Projekte.

War es hilfreich?

Lösung

Die kurze Geschichte ist, dass es keine Standard-Binär-Schnittstelle für C ++ in der Art und Weise, dass es für C. Verschiedene Compiler Ausgabe verschiedener Binärdateien für die gleiche C ++ dynamische Bibliothek ist aufgrund Namen Mangeln und verschiedener Möglichkeiten, um den Stapel zwischen Bibliothek zu handhaben Funktionsaufrufe.

Also, leider nicht wirklich eine tragbare Art und Weise ist C ++ für den Zugriff auf Bibliotheken im Allgemeinen . Aber für einen Compiler zu einer Zeit, dann ist es kein Problem.

Andere Tipps

Neben Boost.Python (was wahrscheinlich ist eine einvernehmliche Lösung für größere Projekte, die eine Eins-zu-Eins-Abbildung von C ++ Klassen Python Klassen erfordern), können Sie auf der Seite ++ C bieten eine C-Schnittstelle. Es ist eine Lösung viele damit es seine eigenen Abwägungen hat, aber ich werde es zum Wohl der Anwesenden, die mit der Technik vertraut sind. Für die vollständige Offenlegung, mit diesem Ansatz wäre man nicht C ++ zu Python, aber C ++ zu C zu Python Schnittstelle. Im Folgenden werde ich eingeschlossen ein Beispiel, das Ihre Anforderungen erfüllt Sie die allgemeine Vorstellung von der extern „c“ Einrichtung von C ++ Compiler zu zeigen.

//YourFile.cpp (compiled into a .dll or .so file)
#include <new> //For std::nothrow
//Either include a header defining your class, or define it here. 

extern "C"  //Tells the compile to use C-linkage for the next scope.
{
    //Note: The interface this linkage region needs to use C only.  
    void * CreateInstanceOfClass( void )
    {
        // Note: Inside the function body, I can use C++. 
        return new(std::nothrow) MyClass;
    }

    //Thanks Chris. 
    void DeleteInstanceOfClass (void *ptr)
    {
         delete(std::nothrow) ptr; 
    }

    int CallMemberTest(void *ptr)
    {

        // Note: A downside here is the lack of type safety. 
        // You could always internally(in the C++ library) save a reference to all 
        // pointers created of type MyClass and verify it is an element in that
        //structure. 
        //
        // Per comments with Andre, we should avoid throwing exceptions.  
        try
        {
            MyClass * ref = reinterpret_cast<MyClass *>(ptr);
            return ref->Test();
        }
        catch(...)
        {
           return -1; //assuming -1 is an error condition. 
        }
    }

} //End C linkage scope.

Sie können diesen Code kompilieren mit

gcc -shared -o test.so test.cpp
#creates test.so in your current working directory.

In Ihrem Python Code, den Sie so etwas wie dieses (interaktive Eingabeaufforderung von 2,7 dargestellt) tun könnte:

>>> from ctypes import cdll
>>> stdc=cdll.LoadLibrary("libc.so.6") # or similar to load c library
>>> stdcpp=cdll.LoadLibrary("libstdc++.so.6") # or similar to load c++ library
>>> myLib=cdll.LoadLibrary("/path/to/test.so")
>>> spam = myLib.CreateInstanceOfClass()
>>> spam
[outputs the pointer address of the element]
>>> value=CallMemberTest(spam)
[does whatever Test does to the spam reference of the object] 

Ich bin sicher, Boost.Python macht etwas Ähnliches unter der Haube, aber vielleicht die unteren Ebenen Konzepte zu verstehen, ist hilfreich. Ich wäre begeistert über diese Methode, wenn Sie Funktionalität einer C ++ Bibliothek zuzugreifen versuchen, und eine Eins-zu-Eins-Abbildung war nicht erforderlich.

Für weitere Informationen über C / C ++ Interaktion Besuche diese Seite von Sun: http : //dsc.sun.com/solaris/articles/mixing.html#cpp_from_c

Die Antwort von AudaAero sehr gut, aber nicht vollständig (zumindest für mich).

Auf meinem System (Debian Stretch x64 mit GCC und G ++ 6.3.0, Python 3.5.3) Ich segfaults so bald hat nenne ich eine Member-Funktion, die zugreifen Wert member der Klasse. I diagnosticirt von Zeigerwerten Druck nach stdout dass die void * Zeiger auf 64 Bits in Umhüllungen codierten auf 32 Bits in Python dargestellt sind. So große Probleme treten auf, wenn es auf eine Elementfunktion Wrapper zurückgegeben.

Die Lösung, die ich gefunden ist zu ändern:

spam = myLib.CreateInstanceOfClass()

In

Class_ctor_wrapper = myLib.CreateInstanceOfClass
Class_ctor_wrapper.restype = c_void_p
spam = c_void_p(Class_ctor_wrapper())

So zwei Dinge fehlten. Setzen des Rückgabetypen c_void_p (die Standardeinstellung ist int) und dann ein c_void_p Objekt erstellen (und nicht nur eine ganze Zahl)

Ich wünsche, ich einen Kommentar geschrieben haben könnte, aber ich fehle noch 27 rep Punkte.

Dies ist eine kurze Erklärung, wie c und C ++ mit C_types in Python. Wie eine DLL / SO in C ++ für Python schreiben

AudaAero der und Gabriel Antwort Devillers ich würde die Klasse Objektinstanz Erstellung und füllen: stdc=c_void_p(cdll.LoadLibrary("libc.so.6")) ctypes c_void_p Datentyp sorgt für die richtige Darstellung des Klassenobjektzeiger innerhalb Python.

Vergewissern Sie sich auch, dass die Speicherverwaltung des DLL von der DLL behandelt werden (zugewiesenen Speicher in der DLL sollte auch in der DLL, und nicht in Python freigegeben werden)!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top