У меня есть интерфейс 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. Я не имею никакого контроля над интерфейсом C - этот код широко используется в других местах.
Я бы хотел вызвать этот код из Python через SWIG , но мне не удалось найти хороших примеров того, как передать указатель на указатель и получить его значение.
Я думаю, что правильный способ сделать это - использовать карты типов, поэтому я определил интерфейс, который будет автоматически разыменовывать p для меня на стороне C:
%typemap(in) void** {
$1 = (void**)&($input);
}
Однако мне не удалось заставить работать следующий код Python:
import test
p = None
theAnswer = 0.0f
if test.Operation(p):
theAnswer = test.GetFieldValue(p)
test.Cleanup(p)
После вызова test.Operation () p всегда сохранял свое начальное значение None.
Буду признателен за любую помощь в поиске правильного способа сделать это в SWIG. В противном случае, я, скорее всего, просто напишу оболочку C ++ вокруг кода C, которая мешает Python иметь дело с указателем. А затем оберните эту оболочку SWIG. Кто-нибудь остановит меня!
Edit:
Благодаря Jorenko , у меня теперь есть следующий интерфейс 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);
}
}
Код Python, который использует этот интерфейс 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) возвращает бессмысленное значение, но test.gfv (p) возвращает правильное значение. Я вставляю код отладки в карту типов для void *, и оба имеют одинаковое значение p! Звонок Есть идеи по этому поводу?
Обновление: Я решил использовать ctypes. НАМНОГО проще.