C到Python通过SWIG:无法获取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,以及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。 更容易。

我同意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能够自己优雅地处理一个简单的by-value void* arg,但为了以防万一,这里的swig代码包含了GetFieldValue()和Cleanup()的void*

 %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)