python - 通过 SWIG : can't get void** parameters to hold their value 从 C 到 Python

标签 python c swig word-wrap

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

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 接口(interface)——该代码在其他地方被广泛使用。

我想通过 SWIG 从 Python 调用这段代码,但我找不到任何关于如何将指针传递给指针并检索其值的好示例。

我认为正确的方法是使用类型映射,所以我定义了一个接口(interface),可以在 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接口(interface)的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* 的类型映射中,并且两者都具有相同的 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 能够自行优雅地处理一个简单的按值 void* arg,但为了以防万一,这里有 swig 代码来包装 void*对于 GetFieldValue() 和 Cleanup():

%typemap (in) void*
{
    $1 = PyCObject_AsVoidPtr($input);
}

关于python - 通过 SWIG : can't get void** parameters to hold their value 从 C 到 Python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/540427/

相关文章:

python - 如何为文本小部件设置字符的最大宽度?

c - C 中的动态双数组

java - 让 SWIG 理解 char** 以便在 Java 中使用它

python - 在 Python SWIG 中包装 void * 参数

c++ - 用 Go 构建包装 C++

python - python "with"语句怎么写?

python - 类变量,instance.var 和 instance.__class__.var 的区别

Python - 从一个非常大的文件中读取随机行并附加到另一个文件

c - c中数组的最大大小

c - 如何在可执行代码中嵌入字符串?