Swig包装typedef结构体

5

尝试包装一个二进制库,其中头文件定义了一个typedef struct x x_t,其中struct x未被定义。如何定义一个接口文件,使得Python可以在下面定义的函数中使用类型定义的结构。

myconnection.h

typedef int myConnectionError;

// Note: this struct does not exist
// The typedef is done to strengthen type checking
typedef struct _myConnectionHandle* myConnectionHandle;

myConnectionError myConnectionOpen( const char *x , const char *y , myConnectionHandle *hand);

myconnection.i

% module myconnection
%{
#include "myconnection.h"
%}

%include "myconnection.h"

工作中的C/C++代码示例

myConnectionHandle chandle;
myConnectionError error;
error = myConnectionOpen("foo","bar",&chandle);

预期的Python代码

import myconnection
handle = myconnection.myConnectionHandle
err = myconnection.myConnectionOpen("foo","1080",handle)

Python结果

Python 2.6.6 (r266:84292, Jan 22 2014, 09:42:36) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import myconnection
>>> handle = myconnection.myConnectionHandle()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'myConnectionnHandle'

typedef struct _myConnectionHandle* myConnectionHandle;的注释很奇怪;它说结构体不存在,但是typedef必须指向一个实际的类/结构体。请问_myConnectionHandle的声明是什么呢?注意(可能与此无关)句柄类型是指向结构体的指针,但参数是指向句柄的指针,这真的是您的意图吗? - Oliver
1
结构体_myConnectionHandle在.h文件中未定义,这是问题的根源。编译后的库内部肯定有此结构体的定义。但使用该库时,只需要处理指向库的指针即可。 - Markus Jonsson
1个回答

1

由于Python不支持输出参数,通常的方法是创建一组类型映射,以抑制必须传递输出参数并代替使用临时值内部附加到返回值。以下是一个最小示例,将句柄转换为Python整数对象并从中获取:

%typemap(in) myConnectionHandle %{
    $1 = (myConnectionHandle)PyLong_AsVoidPtr($input);
%}

%typemap(in,numinputs=0) myConnectionHandle* (void* tmp) %{
    $1 = (myConnectionHandle*)&tmp;
%}
%typemap(argout) myConnectionHandle* %{
    $result = SWIG_Python_AppendOutput($result,PyLong_FromVoidPtr(*$1));
%}

第一个类型映射将Python整数转换为myConnectionHandle,以用作函数的输入。
第二个类型映射告诉SWIG忽略输入参数中的myConnectionHandle*,因为它是输出参数,并在调用函数时仅使用临时值来存储句柄。
第三个类型映射告诉SWIG将返回的句柄值附加到返回结果中,必要时将其转换为[retval,handle]列表。
以下是使用您的myconnection.h的示例,但我添加了一个函数以接受句柄作为输入,并添加了一些虚拟实现函数以使其编译。
%module myconnection
%{
    #include "myconnection.h"
    myConnectionError myConnectionOpen( const char *x , const char *y , myConnectionHandle *hand)
    {
        static int something;
        *hand = (myConnectionHandle)&something;
        return 0;
    }
    void useConnection(myConnectionHandle h)
    {
    }
%}

%typemap(in) myConnectionHandle %{
    $1 = (myConnectionHandle)PyLong_AsVoidPtr($input);
%}

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

%typemap(argout) myConnectionHandle* %{
    $result = SWIG_Python_AppendOutput($result,PyLong_FromVoidPtr(*$1));
%}

%include "myconnection.h"

输出:

>>> import myconnection
>>> retval, handle = myconnection.myConnectionOpen('foo','bar')
>>> myconnection.useConnection(handle)
>>>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接