Как передать байтовый буфер из C++ в Python с помощью SWIG?Python

Программы на Python
Anonymous
Как передать байтовый буфер из C++ в Python с помощью SWIG?

Сообщение Anonymous »

Я использую SWIG версии 4.0.2 в дистрибутиве Ubuntu подсистемы Windows для Linux (WSL). Класс C++, который я хочу обернуть, содержит массив байтов (т. е. каждый элемент массива имеет тип uint8_t или unsigned char). В классе C++ есть метод, выходным параметром которого является двойной указатель, так что вызывающая сторона может получить указатель на этот массив байтов.
Простой класс C++ для переноса представлен следующим образом: заголовочный файл.
example6.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;
}
};
Файл интерфейса SWIG, который я использую для переноса кода C++, выглядит следующим образом.
example6.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), основываясь на хлебных крошках из нескольких примеров. . У меня есть некоторые опасения по поводу них, и я пока не знаю, сработают ли они. Однако это не первое препятствие.
Я не уверен, какой тип переменной Python предоставить в качестве аргумента для метода Message.package() при его вызове. . Я думаю, мне нужно, чтобы переменная имела тип байт. Или, может быть, мне нужны дополнительные директивы %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 "", line 1, in 
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 **'
Исключение TypeError возникает в коде example6_wrap.cxx, созданном SWIG. Исключение происходит задолго до того, как оно получает возможность выполнить фрагмент C++, который вставляет в него указанная выше директива %typemap(argout).
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) иметь много более сложного кода, такого как итерация байтового буфера и ручное копирование его в... что-то еще?
Я искал и собирал примеры из несколько мест, в том числе:
  • Как применить карту типов SWIG для аргумента структуры с двойным указателем
  • SWIG Python — упаковка функция, которая ожидает двойной указатель на структуру.
  • SWIG возвращает байты вместо строки с картой типов.
  • карта типов Swig для Python: входные и выходные массивы< /li>
    Как применить карту типов SWIG _только_ к определенной функции?
  • SWIG 'cstring.i' Python возвращает байтовый тип вместо строкового типа
  • li>
    https://docs.python.org/3.10/c-api/bytearray.html
  • https://docs.python.org/3.10 /c-api/bytes.html


Подробнее здесь: https://stackoverflow.com/questions/790 ... using-swig

Вернуться в «Python»