C到Python通过SWIG:无法获取void**参数来保存它们的值

Jas*_*ram 8 c python swig word-wrap

我有一个看起来像这样的C接口(简化):

extern bool Operation(void ** ppData);
extern float GetFieldValue(void* pData);
extern void Cleanup(p);
Run Code Online (Sandbox Code Playgroud)

使用如下:

void * p = NULL;
float theAnswer = 0.0f;
if (Operation(&p))
{
   theAnswer = GetFieldValue(p);
   Cleanup(p);
}
Run Code Online (Sandbox Code Playgroud)

您将注意到Operation()分配缓冲区p,GetFieldValue查询p,以及Cleanup释放p.我对C接口没有任何控制权 - 该代码在其他地方被广泛使用.

我想通过SWIG从Python调用这段代码,但是我无法找到如何将指针传递给指针的任何好例子 - 并检索它的值.

我认为正确的方法是使用类型映射,所以我定义了一个接口,它会在C端为我自动取消引用p:

%typemap(in) void** {
   $1 = (void**)&($input);
}
Run Code Online (Sandbox Code Playgroud)

但是,我无法使用以下python代码:

import test
p = None
theAnswer = 0.0f
if test.Operation(p):
   theAnswer = test.GetFieldValue(p)
   test.Cleanup(p)
Run Code Online (Sandbox Code Playgroud)

在调用test.Operation()之后,p始终保持其初始值None.

任何帮助找出在SWIG中执行此操作的正确方法将非常感激.否则,我可能只是围绕C代码编写一个C++包装器,阻止Python处理指针.然后使用SWIG 包装包装器.有人阻止我!

编辑:

感谢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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此SWIG接口的python代码如下:

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) 
Run Code Online (Sandbox Code Playgroud)

奇怪的是,在python代码中,test.GetFieldValue(p)返回乱码,但test.gfv(p)返回正确的值.我将调试代码插入到void*的typemap中,并且两者都具有相同的p值!电话有任何想法吗?

更新:我决定使用ctypes.更容易.

Jor*_*nko 7

我同意theller,你应该使用ctypes.它总是比考虑类型图更容易.

但是,如果您已经开始使用swig,那么您需要做的是为void**新分配的RETURNS 创建一个类型映射void*:

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

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

然后你的python看起来像:

import test
success, p = test.Operation()
theAnswer = 0.0f
if success:
   theAnswer = test.GetFieldValue(p)
   test.Cleanup(p)
Run Code Online (Sandbox Code Playgroud)

编辑:

我希望swig可以void*自己优雅地处理一个简单的按值arg,但为了以防万一,这里有swig代码来包装void*GetFieldValue()和Cleanup():

%typemap (in) void*
{
    $1 = PyCObject_AsVoidPtr($input);
}
Run Code Online (Sandbox Code Playgroud)