C에서 SWIG를 통해 Python에서 : void를 얻을 수 없음 ** 값을 유지하기 위해 매개 변수

StackOverflow https://stackoverflow.com/questions/540427

  •  22-08-2019
  •  | 
  •  

문제

다음과 같은 것처럼 보이는 C 인터페이스가 있습니다 (단순화).

extern bool Operation(void ** ppData);
extern float GetFieldValue(void* pData);
extern void Cleanup(p);

다음과 같이 사용됩니다.

void * p = NULL;
float theAnswer = 0.0f;
if (Operation(&p))
{
   theAnswer = GetFieldValue(p);
   Cleanup(p);
}

Operation ()는 버퍼 P, 그 getfieldValue p를 쿼리하고 정리 p를 할당합니다. p. C 인터페이스를 제어 할 수 없습니다. 해당 코드는 다른 곳에서 널리 사용됩니다.

Python Via 에서이 코드를 호출하고 싶습니다 통음, 그러나 포인터를 포인터로 전달하는 방법에 대한 좋은 예를 찾을 수 없었습니다.

이 작업을 수행하는 올바른 방법은 TypEmap을 사용하는 것이므로 C 측에서 나에게 자동으로 P를 방해하는 인터페이스를 정의했습니다.

%typemap(in) void** {
   $1 = (void**)&($input);
}

그러나 다음과 같은 파이썬 코드를 작동시킬 수 없었습니다.

import test
p = None
theAnswer = 0.0f
if test.Operation(p):
   theAnswer = test.GetFieldValue(p)
   test.Cleanup(p)

Test.Operation ()을 호출 한 후 P는 항상 초기 값을 없애지 않았습니다.

SWIG 에서이 작업을 수행하는 올바른 방법을 알아내는 데 도움이되는 것은 대단히 감사 할 것입니다. 그렇지 않으면, 나는 Python이 포인터를 처리하지 않아도되는 C 코드 주위에 C ++ 래퍼를 작성할 수 있습니다. 그리고 랩 저것 SWIG가있는 래퍼. 누군가 나를 막아!

편집하다:

감사합니다 조렌코, 이제 다음과 같은 SWIG 인터페이스가 있습니다.

% module Test 
%typemap (in,numinputs=0) void** (void *temp)
{
    $1 = &temp;
}

%typemap (argout) void**
{
    PyObject *obj = PyCObject_FromVoidPtr(*$1, Cleanup);
    $result = PyTuple_Pack(2, $result, obj);
}
%{
extern bool Operation(void ** ppData); 
extern float GetFieldValue(void *p); 
extern void Cleanup(void *p);
%} 
%inline 
%{ 
    float gfv(void *p){ return GetFieldValue(p);} 
%} 

%typemap (in) void*
{
    if (PyCObject_Check($input))
    {
        $1 = PyCObject_AsVoidPtr($input);
    }
}

이 SWIG 인터페이스를 사용하는 파이썬 코드는 다음과 같습니다.

import test 
success, p = test.Operation()
if success:
   f = test.GetFieldValue(p) # This doesn't work 
   f = test.gvp(p) # This works! 
   test.Cleanup(p) 

이상하게도 Python 코드에서 Test.getFieldValue (P)는 Gibberish를 반환하지만 Test.gfv (P)는 올바른 값을 반환합니다. void*의 TypeMap에 디버깅 코드를 삽입하고 있으며 둘 다 P의 값이 동일합니다! 그것에 대한 아이디어가 있습니까?

업데이트: 나는 ctypes를 사용하기로 결정했습니다. 훨씬 쉽게.

도움이 되었습니까?

해결책

나는 Theller에 동의합니다. 대신 CTypes를 사용해야합니다. 타입 맵에 대해 생각하는 것보다 항상 쉽습니다.

그러나 Swig를 사용하는 것으로 죽었다면, 당신이해야 할 일은 typemap을 만드는 것입니다. void** 새로 할당 된 것을 반환합니다 void*:

%typemap (in,numinputs=0) void** (void *temp)
{
    $1 = &temp;
}

%typemap (argout) void**
{
    PyObject *obj = PyCObject_FromVoidPtr(*$1);
    $result = PyTuple_Pack(2, $result, obj);
}

그런 다음 파이썬은 다음과 같습니다.

import test
success, p = test.Operation()
theAnswer = 0.0f
if success:
   theAnswer = test.GetFieldValue(p)
   test.Cleanup(p)

편집하다:

나는 SWIG가 간단한 값을 처리 할 것으로 기대합니다 void* Arg는 그 자체로 우아하게, 그러나 만일을 대비하여, 여기에 Swig 코드가 있습니다. void* getfieldValue () 및 cleanup ()의 경우 :

%typemap (in) void*
{
    $1 = PyCObject_AsVoidPtr($input);
}

다른 팁

CTypes를 기꺼이 사용 하시겠습니까? 다음은 작동 해야하는 샘플 코드입니다 (테스트되지 않았지만) :

from ctypes import *

test = cdll("mydll")

test.Operation.restype = c_bool
test.Operation.argtypes = [POINTER(c_void_p)]

test.GetFieldValue.restype = c_float
test.GetFieldValue.argtypes = [c_void_p]

test.Cleanup.restype = None
test.Cleanup.argtypes = [c_void_p]

if __name__ == "__main__":
    p = c_void_p()
    if test.Operation(byref(p)):
        theAnswer = test.GetFieldValue(p)
        test.Cleanup(p)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top