C에서 SWIG를 통해 Python에서 : void를 얻을 수 없음 ** 값을 유지하기 위해 매개 변수
문제
다음과 같은 것처럼 보이는 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)