복붙노트

[PYTHON] ctypes에 C ++ 클래스를 사용하는 방법?

PYTHON

ctypes에 C ++ 클래스를 사용하는 방법?

난 그냥 ctypes 시작하고있어 내가 ctypes 사용하여 파이썬 내에서 dll 파일을 내 보낸 C ++ 클래스를 사용하고 싶습니다. 그래서 내 C ++ 코드는 다음과 같이 보일 것입니다.

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

이 클래스를 포함하는 .dll 파일을 만든 다음 ctypes를 사용하여 python으로 .dll 파일을로드합니다. 이제 MyClass 유형의 Object를 만들고 테스트 함수를 호출하는 방법은 무엇입니까? 그것은 심지어 ctypes로 가능합니까? 또는 SWIG 또는 Boost.Python을 사용하는 것이 좋지만 ctypes는 작은 프로젝트에서 가장 쉬운 옵션처럼 보입니다.

해결법

  1. ==============================

    1.단편은 C와 같은 방식으로 C ++ 용 표준 바이너리 인터페이스가 없다는 것입니다. 다른 컴파일러는 이름 변환과 라이브러리 함수 호출간에 스택을 처리하는 다양한 방법으로 인해 동일한 C ++ 동적 라이브러리에 대해 서로 다른 바이너리를 출력합니다.

    단편은 C와 같은 방식으로 C ++ 용 표준 바이너리 인터페이스가 없다는 것입니다. 다른 컴파일러는 이름 변환과 라이브러리 함수 호출간에 스택을 처리하는 다양한 방법으로 인해 동일한 C ++ 동적 라이브러리에 대해 서로 다른 바이너리를 출력합니다.

    불행히도 일반적으로 C ++ 라이브러리에 액세스 할 수있는 이식성있는 방법은 없습니다. 그러나 한 번에 하나의 컴파일러 만 있으면 아무런 문제가 없습니다.

    이 블로그 게시물에는 현재 이것이 작동하지 않는 이유에 대한 간략한 개요가 있습니다. 어쩌면 C ++ 0x가 나오면 C ++ 용으로 표준 ABI를 갖게 될까요? 그때까지는 파이썬의 ctype을 통해 C ++ 클래스에 액세스 할 수있는 방법이 없을 것입니다.

  2. ==============================

    2.Boost.Python (아마도 파이썬 클래스에 C ++ 클래스의 일대일 매핑을 요구하는 더 큰 프로젝트에 더 친숙한 솔루션 일 것입니다.), C ++ 측에 C 인터페이스를 제공 할 수 있습니다. 그것은 하나의 솔루션이기 때문에 많은 트레이드 오프가 있지만이 기술에 익숙하지 않은 사람들을 위해 제시 할 것입니다. 전체 공개를 위해,이 접근법을 사용하면 C ++을 파이썬과 인터페이싱하지 않을 것이지만 C ++에서 C to Python으로 인터페이싱 할 것입니다. 아래에는 C ++ 컴파일러의 extern "c"기능에 대한 일반적인 아이디어를 보여주기위한 요구 사항을 충족하는 예제가 포함되어 있습니다.

    Boost.Python (아마도 파이썬 클래스에 C ++ 클래스의 일대일 매핑을 요구하는 더 큰 프로젝트에 더 친숙한 솔루션 일 것입니다.), C ++ 측에 C 인터페이스를 제공 할 수 있습니다. 그것은 하나의 솔루션이기 때문에 많은 트레이드 오프가 있지만이 기술에 익숙하지 않은 사람들을 위해 제시 할 것입니다. 전체 공개를 위해,이 접근법을 사용하면 C ++을 파이썬과 인터페이싱하지 않을 것이지만 C ++에서 C to Python으로 인터페이싱 할 것입니다. 아래에는 C ++ 컴파일러의 extern "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 ++ 상호 작용에 대한 자세한 내용은 Sun의이 페이지를 확인하십시오. http://dsc.sun.com/solaris/articles/mixing.html#cpp_from_c

  3. ==============================

    3.AudaAero의 대답은 매우 좋지만 완료되지 않았습니다 (최소한 나를 위해).

    AudaAero의 대답은 매우 좋지만 완료되지 않았습니다 (최소한 나를 위해).

    내 시스템 (GCC와 G ++ 6.3.0, 파이썬 3.5.3을 사용하는 데비안 스트레치 x64)에서는 클래스의 멤버 값에 액세스하는 멤버 함수를 곧 호출 할 것이므로 segfaults가 있습니다. 필자는 포인터 값을 stdout으로 출력하여 래퍼의 64 비트에 코딩 된 void * 포인터가 파이썬에서 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 (기본값은 int)로 설정 한 다음 c_void_p 객체 (정수가 아님)를 만드는 두 가지 방법이 없습니다.

    나는 내가 코멘트를 썼을 수 있었 더라면 좋겠지 만 나는 아직도 27의 rep 지점이 없다.

  4. ==============================

    4.이것은 파이썬에서 C 및 C ++을 C_types와 함께 사용하는 방법에 대한 간단한 설명입니다. Python 용 C ++에서 DLL / SO를 작성하는 방법

    이것은 파이썬에서 C 및 C ++을 C_types와 함께 사용하는 방법에 대한 간단한 설명입니다. Python 용 C ++에서 DLL / SO를 작성하는 방법

  5. ==============================

    5.AudaAero 및 Gabriel Devillers 확장 답변 클래스 객체 인스턴스 생성을 완료하려면 다음을 수행합니다. stdc = c_void_p (cdll.LoadLibrary ( "libc.so.6")) ctypes 사용하기 c_void_p 데이터 타입은 파이썬 안에서 클래스 객체 포인터의 올바른 표현을 보장합니다.

    AudaAero 및 Gabriel Devillers 확장 답변 클래스 객체 인스턴스 생성을 완료하려면 다음을 수행합니다. stdc = c_void_p (cdll.LoadLibrary ( "libc.so.6")) ctypes 사용하기 c_void_p 데이터 타입은 파이썬 안에서 클래스 객체 포인터의 올바른 표현을 보장합니다.

    또한 dll의 메모리 관리가 dll에 의해 처리되는지 확인하십시오 (dll에 할당 된 메모리는 dll에서 할당 취소되어야하며 python에서는 할당 해제되어야합니다).

  6. from https://stackoverflow.com/questions/1615813/how-to-use-c-classes-with-ctypes by cc-by-sa and MIT license