我有一个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,以及Cleanup释放p。我对C接口没有任何控制权 - 该代码在其他地方被广泛使用。
我想通过SWIG从Python调用此代码,但我无法找到如何将指针传递给指针的任何好例子 - 并检索其值。
我认为正确的方法是使用类型地图,所以我定义了一个接口,它会在C端为我自动取消引用p:
%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包装 包装器。有人阻止我!
编辑:
感谢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);
}
}
使用此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)
奇怪的是,在python代码中,test.GetFieldValue(p)返回乱码,但test.gfv(p)返回正确的值。我将调试代码插入到void *的typemap中,并且两者都具有相同的p值!电话有任何想法吗?
更新:我决定使用ctypes。更容易。
答案 0 :(得分:7)
我同意theller,你应该使用ctypes。它总是比考虑类型图更容易。
但是,如果您已经决定使用swig,那么您需要做的是为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);
}
然后你的python看起来像:
import test
success, p = test.Operation()
theAnswer = 0.0f
if success:
theAnswer = test.GetFieldValue(p)
test.Cleanup(p)
编辑:
我希望swig能够自己优雅地处理一个简单的按值void*
arg,但为了以防万一,这里的swig代码用于包装GetFieldValue()和Cleanup()的void*
:
%typemap (in) void*
{
$1 = PyCObject_AsVoidPtr($input);
}
答案 1 :(得分:4)
你愿意使用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)