سؤال

أنا مجرد الحصول بدأت مع ctypes و ترغب في استخدام فئة C++ التي يجب تصديرها في ملف dll من داخل الثعبان باستخدام ctypes.لذلك دعونا نقول بلدي رمز C++ تبدو شيئا مثل هذا:

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

أود أن أعرف خلق .ملف dll الذي يحتوي على هذه الفئة ومن ثم تحميل .ملف dll في بيثون باستخدام ctypes.الآن كيف يمكنني إنشاء كائن من نوع MyClass و استدعاء اختبار وظيفة ؟ هل هذا ممكن مع ctypes?بدلا من ذلك وأود أن تنظر في استخدام جرعة كبيرة أو دفعة.الثعبان ولكن ctypes يبدو الخيار الأسهل للمشروعات الصغيرة.

هل كانت مفيدة؟

المحلول

والقصة القصيرة هي أنه لا يوجد أي واجهة ثنائية القياسية لC ++ في الطريقة التي يوجد لC. المجمعين مختلفة الانتاج ثنائيات مختلفة للمكتبات ديناميكية في نفس C ++، بسبب اسم تغيير اسم وطرق مختلفة للتعامل مع كومة بين مكتبة المكالمات وظيفة.

وهكذا، للأسف، ليس هناك في الحقيقة ليست وسيلة المحمولة للوصول إلى C ++ المكتبات في عام . ولكن، للمترجم واحد في وقت واحد، فإنه ليس من المشكلة.

<أ href = على "http://blog.vrplumber.com/index.php؟/archives/197-Ctypes-for-C++-is-going-to-be-a-pain-due-to-politics -Bothering باللغة المبدعين هو بين المتعة .... أتش تي أم أل "يختلط =" noreferrer "> هذا بلوق وظيفة أيضا لمحة قصيرة عن سبب هذا سوف حاليا لا تعمل. ربما بعد C ++ 0X يخرج، سيكون لدينا ABI القياسي لC ++؟ حتى ذلك الحين، وربما كنت لن يكون لها أي وسيلة للوصول C ++ الطبقات من خلال ctypes بايثون.

نصائح أخرى

وإلى جانب Boost.Python (والتي من المحتمل ان يكون حل أكثر ودية للمشاريع الكبرى التي تتطلب واحد الى واحد رسم الخرائط من فئات C ++ إلى الطبقات الثعبان)، هل يمكن أن تقدم على C ++ جانب واجهة C. انها حل واحد من كثير لذلك فقد المفاضلة الخاصة بها، ولكنني لن تقديمه لصالح أولئك الذين ليسوا على دراية تقنية. لالكشف الكامل، مع هذا النهج واحد لن يكون التواصل C ++ إلى الثعبان، ولكن C ++ C للبيثون. أدناه I اشتملت على سبيل المثال أن تلبي الاحتياجات الخاصة بك لتظهر لك فكرة عامة عن خارجي "ج" منشأة من المجمعين C ++.

//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.

ويمكنك تجميع هذا الرمز مع

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

في كود الثعبان الخاصة بك هل يمكن أن تفعل شيئا من هذا القبيل (موجه التفاعلية من 2.7 معروضة):

>>> 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] 

وأنا متأكد Boost.Python يفعل شيئا من هذا القبيل تحت غطاء محرك السيارة، ولكن ربما فهم المفاهيم مستويات أقل من المفيد. سأكون أكثر حماسة لهذا الأسلوب إذا كنت تحاول الوصول إلى وظائف مكتبة C ++ و لم يكن مطلوبا تعيين واحد الى واحد.

لمزيد من المعلومات حول C / C ++ التفاعل تحقق من هذه الصفحة من الشمس: HTTP : //dsc.sun.com/solaris/articles/mixing.html#cpp_from_c

على الجواب من خلال AudaAero هو جيد جدا ولكن ليس كاملة (على الأقل بالنسبة لي).

على نظام (دبيان تمتد إلى x64 مع دول مجلس التعاون الخليجي و G++ 6.3.0 ، بيثون 3.5.3) لدي segfaults في أقرب وقت وقد أتصل وظيفة عضو أن الوصول عضو القيمة من الطبقة.أنا diagnosticated قبل الطباعة مؤشر قيم المعياري أن الفراغ* مؤشر مشفرة على 64 بت في أغلفة هو أن تكون ممثلة على 32 بت في بيثون.وبالتالي مشاكل كبيرة تحدث عندما يتم تمريرها إلى وظيفة عضو المجمع.

الحل وجدته هو تغيير:

spam = myLib.CreateInstanceOfClass()

في

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

حتى شيئين في عداد المفقودين:تحديد نوع الإرجاع إلى c_void_p (الافتراضي هو الباحث) و ثم خلق c_void_p كائن (وليس فقط عدد صحيح).

أتمنى أن قد كتبت التعليق ولكن أنا لا تزال تفتقر إلى 27 مندوب نقطة.

وهذا هو شرحا موجزا حول كيفية استخدام C و C ++ مع C_types في بيثون. كيفية كتابة DLL / SO في C ++ لبيثون

AudaAero في و غابرييل Devillers الإجابة أود أن إكمال إنشاء مثيل كائن الفئة عن طريق: stdc=c_void_p(cdll.LoadLibrary("libc.so.6")) باستخدام نوع ctypes البيانات c_void_p يضمن التمثيل الصحيح للمؤشر كائن فئة داخل الثعبان.

وأيضا تأكد من أن يتم التعامل معها إدارة الذاكرة ودلل دلل من قبل (الذاكرة المخصصة في DLL يجب أن يمكن deallocated أيضا في دلل، وليس في الثعبان)!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top