如何使用 SWIG 将字节缓冲区从 C++ 传递到 Python?

问题描述 投票:0回答:1

我在 Windows Linux 子系统 (WSL) Ubuntu 发行版中使用 SWIG 版本 4.0.2。 我想要包装的 C++ 类包含一个字节数组(即数组中的每个项目的类型为

uint8_t
unsigned char
)。 C++ 类有一个方法,其输出参数是双指针,以便调用者可以获得指向该字节数组的指针。

要包装的简单 C++ 类由以下头文件表示。

示例6.h
#pragma once

class Message
{
private:
  uint8_t * m_data;
  int m_size;

public:
  Message( void )
  : m_data( NULL )
  , m_size( 0 )
  {
    m_data = new uint8_t[3]();
    m_data[0] = 'A';
    m_data[1] = 'B';
    m_data[2] = 'C';
    m_size = 3;
  }

  virtual ~Message( void )
  {
    delete[] m_data;
  }

  int package( uint8_t** buf )
  {
    *buf = NULL;
    int size = 0;
    if ( m_data )
    {
      *buf = m_data;
      size = m_size;
    }

    return size;
  }
};

我用来包装 C++ 代码的 SWIG 接口文件如下。

示例6.swg
%module example6

%{
  #define SWIG_FILE_WITH_INIT

  #include "example6.h"
%}

%typemap( in, numinputs=0 ) ( uint8_t** buf )
{
  uint8_t** temp = 0x0;
  $1 = temp;
}

%typemap( argout ) ( uint8_t** buf )
{
  if ( *$1 )
  {
    $result = PyBytes_FromString( (char *)( *$1 ) );
    free( *$1 );
  }
}

%include "example6.h"

在 SWIG 接口文件中,我尝试根据几个示例中的面包屑使用适当的

%typemap(in)
%typemap(argout)
指令。 我对它们有一些担忧,但还不知道它们是否有效。 然而,这些并不是第一个障碍。

当我调用

Message.package()
方法时,我不确定要提供什么类型的 Python 变量作为参数。 我想我希望变量的类型为
bytes
。 或者,也许我需要额外的
%typemap
指令才能将 Python
bytes
变量正确转换为 C++
uint8_t**
变量?

以下是问题的演示。

finch@laptop:~/work/swig_example$ python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import example6
>>> m = example6.Message()
>>> b = bytes()
>>> b
b''
>>> m.package( b )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/finch/work/swig_example/example6.py", line 73, in package
    return _example6.Message_package(self, buf)
TypeError: in method 'Message_package', argument 2 of type 'uint8_t **'

SWIG 生成的

TypeError
代码中引发了
example6_wrap.cxx
异常。 异常发生在它有机会执行上面的
%typemap(argout)
指令注入的 C++ 代码片段之前。

example6_wrap.cxx
SWIGINTERN PyObject *_wrap_Message_package(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
  PyObject *resultobj = 0;
  Message *arg1 = (Message *) 0 ;
  uint8_t **arg2 = (uint8_t **) 0 ;
  void *argp1 = 0 ;
  int res1 = 0 ;
  void *argp2 = 0 ;
  int res2 = 0 ;
  PyObject *swig_obj[2] ;
  int result;

  if (!SWIG_Python_UnpackTuple(args, "Message_package", 2, 2, swig_obj)) SWIG_fail;
  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Message, 0 |  0 );
  if (!SWIG_IsOK(res1)) {
    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Message_package" "', argument " "1"" of type '" "Message *""'"); 
  }
  arg1 = reinterpret_cast< Message * >(argp1);
  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2,SWIGTYPE_p_p_uint8_t, 0 |  0 );
  if (!SWIG_IsOK(res2)) {
    //*** Finch temp: This is where the TypeError exception will be raised.
    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Message_package" "', argument " "2"" of type '" "uint8_t **""'"); 
  }
  arg2 = reinterpret_cast< uint8_t ** >(argp2);
  result = (int)(arg1)->package(arg2);
  resultobj = SWIG_From_int(static_cast< int >(result));

  //*** Finch temp: This is the snippet that the %typemap(argout) directive injects.
  {
    if ( *arg2 )
    {
      resultobj = PyBytes_FromString( (char *)( *arg2 ) );
      free( *arg2 );
    }
  }
  //***

  return resultobj;
fail:
  return NULL;
}

问题1

什么类型映射可以帮助我将 Python

bytes
变量转换为 C++
uint8_t**
变量。

问题2

PyBytes_FromString()
期望获得一个
char const *
变量。 但我正在包装的真实 C++ 库中的底层消息数据是
uint8_t
; 我被困住了。 我担心盲目重铸会导致某些字节值错误。 还有其他
PyBytes_something()
功能我没见过吗?

如果不是,

%typemap(argout)
指令中包含很多更多涉及的代码是否合适,例如迭代字节缓冲区并手动将其复制到......其他地方?

我一直在寻找并拼凑来自多个地方的示例,包括:

python c++ swig
1个回答
0
投票

我有一个不涉及使用更好的类型映射的拼凑; 而且,它是 Python 特有的。 它足以满足我的需求,但不能解决一般问题。

在 SWIG 接口文件中,我在内联代码插入块中添加了一个辅助函数。 辅助函数本质上是 Finch 生成的

Message::package()
方法的包装器,它依赖于我对 SWIG 生成的包装器代码如何工作的了解。

示例6.swg
%module example6

...

%inline %{
  PyObject * Message_package_helper( Message * pMsg )
  {
    PyObject * pResult = 0x0;
    if ( pMsg )
    {
      uint8_t * pData;
      int size = pMsg->package( &pData );
      pResult = PyBytes_FromStringAndSize( (char *)( pData ), size );
    }

    return pResult;
  }
%}

...

以下是其工作原理的演示。

finch@laptop:~/work/swig_example$ python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import example6
>>> m = example6.Message()
>>> b = example6.Message_package_helper( m )
>>> b
b'ABC'

我阅读了有关 SWIG 代码插入块、辅助函数和内联的文档:

© www.soinside.com 2019 - 2024. All rights reserved.