我有一个类似这样的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++包装器,以防止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。简单得多。
p
同时是 'void**' 和 'void*'。None
是不可变的,因此无论如何p
引用的对象都不会改变(尽管你可以使用=
将p
绑定到另一个对象)。