Swig和指针问题(python)

时间:2017-10-24 12:21:52

标签: python c++ swig

我正在使用Swig为DLL文件生成python包装器。我所做的是:

  1. 使用swig -c++ -python myfile.i
  2. 生成包装器和加载器文件
  3. 创建一个新的DLL文件,包含myfile_wrapper.cxx和 编译为_myfile.pyd。
  4. 在Idle中加载由Swig创建的模块myfile.py并尝试使用它。
  5. 接口文件如下所示:

    %module myfile 
    /* Make a test with cpointer - needed?? */
    %include cpointer.i 
    %pointer_functions(MyHandle, my_handle_p);
    %pointer_class(int, intp);
    %{
    #define SWIG_FILE_WITH_INIT
    #include "MyFile.h"
    }%
    %include "MyFile.h"
    

    该功能看起来像

     typedef struct tagMyHandle
       {
          void* reserved;
       } *MyHandle;
    
    int OpenFile(const char *szPath, MyHandle* pFile); // pFile is an out parameter
    int GetNumberOfItems(MyHandle hFile, int *pnNrOfItems); // pnNrOfItems is an out parameter
    

    如果我尝试从Python中使用它,我必须这样做:

    import myfile
    handle_p = myfile.new_my_handle_p()
    myfile.OpenFile("Path", handle_p)
    handle = myfile.my_file_p_value(handle_p)
    num_items_p = myfile.new_intp()
    myfile.GetNumberOfItems(handle, num_items_p)
    num_items = num_items_p.value()
    

    我是否正确使用Swig?感觉这是一种非常麻烦的方式来调用应该为Python包装的函数。

    我想做点什么:

    result, handle = OpenFile("path")
    result, items = GetNumberIfItems(handle)
    

    我无法更改myfile.h的源代码。

    我看了input/output parameters,但我是否必须为每种输出类型定义它们? MyFile.h有数百个具有不同输出类型的函数。它只支持原始数据类型,但MyFile.h中的大多数类型都不是原始类型,而是像结构MyHandle一样。

    我也看过SWIG function with pointer structhttp://www.swig.org/Doc3.0/Python.html#Python_nn18,但没有任何好的解决方案。

    更新1 经过很多帮助后,我已经解决了大部分问题,但我仍然有一些我不明白的问题。

    问题1:

    // For the out parameter, shouldn't be needed?
    %typemap(in,numinputs=0) MyHandle* pOutParam (MyHandle h) %{
        $1 = &h;
    %}
    
    // For all others
    %typemap(in,numinputs=0) MyHandle* (MyHandle h) %{
        $1 = &h;
    %}
    
    // For the return type
    %typemap(argout) MyHandle* pOutParam (PyObject* o) %{
        o = PyLong_FromVoidPtr(*$1);
        $result = SWIG_Python_AppendOutput($result,o);
    %}
    
    %typemap(in) MyHandle %{
        $1 = reinterpret_cast<MyHandle>(PyLong_AsVoidPtr($input));
    %}
    

    和代码

    int OpenFile(const char *szPath, MyHandle* pOutParam);
    int DoSomething(MyHandle* pInParam);
    

    OpenFile就像魅力一样,但DoSomething仍尝试返回MyHandle而不是将其作为参数,我不明白为什么。 %typemap(argout) MyHandle*仅定义为pOutParam

    问题2: 我不明白如何制作像

    这样的类型地图
    int GetFileName(char *szPathBuffer, int iLength);
    

    如何创建一个char缓冲区并将其发送到,如I C:

    char szBuffer[MAX_PATH]; GetFileName(szBuffer, MAX_PATH);
    

    也许和cstring_bounded_output一起或者我应该做点什么

    %typemap(in) (char*, int) { 
        $2 = PyString_Size($input); 
        $1 = (char*) malloc($2 * sizeof(char*)); 
    } 
    

    但它在何处被解除分配?

    问题3: 枚举值的正确映射是什么。如果我有

    typedef enum tagMyEnum {
    MyTrue = 1,
    MyFalse = 0 } MyEnum;
    

    和功能

    int IsCorrect(MyEnum* pOutValue);
    

    @Mark Tolonen: 谢谢大家的帮助!对此,我真的非常感激!我学到了很多关于Swig的新东西!

1 个答案:

答案 0 :(得分:1)

这是一个示例,其界面类似于您想要使用类型图重新定义界面的说明:

<强> myfile.h

typedef struct tagMyHandle
{
    void* reserved;
} *MyHandle;

int OpenFile(const char *szPath, MyHandle* pFile);
int GetNumberOfItems(MyHandle hFile, int *pnNrOfItems);
// Added this to free the allocated handle.
void CloseFile(MyHandle hFile);

<强> MYFILE.CPP

标题的黑客实现......

#include "myfile.h"

int OpenFile(const char *szPath, MyHandle* pFile)
{
    *pFile = new tagMyHandle;
    (*pFile)->reserved = new int(7);
    return 1;
}

int GetNumberOfItems(MyHandle hFile, int *pnNrOfItems)
{
    *pnNrOfItems = *reinterpret_cast<int*>(hFile->reserved) + 5;
    return 1;
}

// mirrors OpenFile to free the allocated handle.
void CloseFile(MyHandle hFile)
{
    delete reinterpret_cast<int*>(hFile->reserved);
    delete hFile;
}

<强> myfile.i

%module myfile 

%{
#include "MyFile.h"
%}

// An input typemap for the an output parameter, called before the C++ function is called.
// It suppresses requiring the parameter from Python, and uses a temporary
// variable to hold the output value.
%typemap(in,numinputs=0) MyHandle* (MyHandle h) %{
    $1 = &h;
%}

// An output argument typemap, called after the C++ function is called.
// It retrieves the output value and converts it to a Python int,
// then appends it to the existing return value.  Python will get a tuple of
// (return_value,handle).
%typemap(argout) MyHandle* (PyObject* o) %{
    o = PyLong_FromVoidPtr(*$1);
    $result = SWIG_Python_AppendOutput($result,o);
%}

// An input typemap that converts a Python int to a MyHandle*.
%typemap(in) MyHandle %{
    $1 = reinterpret_cast<MyHandle>(PyLong_AsVoidPtr($input));
%}

// This applies a pre-defined int* output typemap to all int* parameters.
%apply int *OUTPUT {int *};

%include "MyFile.h"

<强>输出

>>> import myfile
>>> s,h = myfile.OpenFile('path')
>>> s,h
(1, 7706832)
>>> s,v = myfile.GetNumberOfItems(h)
>>> s,v
(1, 12)
>>> myfile.CloseFile(h)