我在 Windows Linux 子系统 (WSL) Ubuntu 发行版中使用 SWIG 版本 4.0.2。 我想要包装的 C++ 类包含一个字节数组(即数组中的每个项目的类型为
uint8_t
或 unsigned char
)。 C++ 类有一个方法,其输出参数是双指针,以便调用者可以获得指向该字节数组的指针。
要包装的简单 C++ 类由以下头文件表示。
#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 接口文件如下。
%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++ 代码片段之前。
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;
}
什么类型映射可以帮助我将 Python
bytes
变量转换为 C++ uint8_t**
变量。
PyBytes_FromString()
期望获得一个 char const *
变量。 但我正在包装的真实 C++ 库中的底层消息数据是 uint8_t
; 我被困住了。 我担心盲目重铸会导致某些字节值错误。 还有其他PyBytes_something()
功能我没见过吗?
如果不是,
%typemap(argout)
指令中包含很多更多涉及的代码是否合适,例如迭代字节缓冲区并手动将其复制到......其他地方?
我一直在寻找并拼凑来自多个地方的示例,包括:
我有一个不涉及使用更好的类型映射的拼凑; 而且,它是 Python 特有的。 它足以满足我的需求,但不能解决一般问题。
在 SWIG 接口文件中,我在内联代码插入块中添加了一个辅助函数。 辅助函数本质上是 Finch 生成的
Message::package()
方法的包装器,它依赖于我对 SWIG 生成的包装器代码如何工作的了解。
%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 代码插入块、辅助函数和内联的文档: