SWIG Python C++ 结构作为 in/out 参数
SWIG Python C++ struct as in/out parameter
老实说,我阅读并重读了本网站上有关 struct 主题的很多 post。但是我需要你的帮助。
我有 C 风格的结构
struct Time
{
uint16_t year; // year with four digits like 2016
uint8_t month; // 1 .. 12
uint8_t day; // 1 .. 31
uint8_t hour; // 0 .. 23, 24 hour representation
uint8_t minute; // 0 .. 59
uint8_t second; // 0 .. 59
};
和class带有成员函数,其实现在DLL中。
class DeviceInterface {
virtual uint32_t getTime(Time& time) = 0;
};
其中 uint32_t 值为状态代码。
这里是自动生成的 SWIG C++ 代码:
SWIGINTERN PyObject *_wrap_getTime(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *resultobj = 0;
DeviceInterface *arg1 = (DeviceInterface *) 0 ;
Time *arg2 = 0 ;
void *argp1 = 0 ;
int res1 = 0 ;
void *argp2 = 0 ;
int res2 = 0 ;
PyObject *swig_obj[2] ;
uint32_t result;
if (!SWIG_Python_UnpackTuple(args, "getTime", 2, 2, swig_obj)) SWIG_fail;
res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_DeviceInterface, 0 | 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "getTime" "', argument " "1"" of type '" "DeviceInterface *""'");
}
arg1 = reinterpret_cast< DeviceInterface * >(argp1);
res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_Time, 0 );
if (!SWIG_IsOK(res2)) {
SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "getTime" "', argument " "2"" of type '" "Time &""'");
}
if (!argp2) {
SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "getTime" "', argument " "2"" of type '" "Time &""'");
}
arg2 = reinterpret_cast< Time * >(argp2);
result = (uint32_t)(arg1)->getTime(*arg2);
resultobj = SWIG_From_unsigned_SS_int(static_cast< unsigned int >(result));
return resultobj;
fail:
return NULL;
}
从上面的代码中我看不到什么时间值,即 arg2 变量,不知何故被返回。那么我需要在 SWIG 接口文件中编写什么来获取状态代码和 time?
您可以编写一个类型映射来附加 Time
输出参数。 SWIG 为可以根据需要通过 SWIG_NewPointerObj()
生成的结构生成代理。完整示例如下:
DeviceInterface.h(最小实现)
#include <stdint.h>
struct Time
{
uint16_t year; // year with four digits like 2016
uint8_t month; // 1 .. 12
uint8_t day; // 1 .. 31
uint8_t hour; // 0 .. 23, 24 hour representation
uint8_t minute; // 0 .. 59
uint8_t second; // 0 .. 59
};
class DeviceInterface {
public:
virtual uint32_t getTime(Time& time) {
time.year = 2021;
time.month = 12;
time.day = 30;
time.hour = 9;
time.minute = 47;
time.second = 30;
return 0;
}
};
test.i
%module test
%{
#include "DeviceInterface.h"
%}
%include <stdint.i>
// Do not require an input parameter for Time.
// Instead, SWIG will allocate one.
%typemap(in,numinputs=0) Time& %{
= new Time;
%}
// After calling the function, process Time as an output.
// Convert the allocated pointer to a SWIG Python wrapper
// and pass ownership to Python. Python will free the object
// when it goes out of scope.
%typemap(argout) Time& (PyObject* tmp) %{
// Convert C pointer to SWIG Python wrapper
tmp = SWIG_NewPointerObj(, _descriptor, SWIG_POINTER_OWN);
// Append to existing uint32_t return value
$result = SWIG_Python_AppendOutput($result, tmp);
%}
%include "DeviceInterface.h"
演示:
>>> import test
>>> d=test.DeviceInterface()
>>> r=d.getTime()
>>> r
[0, <test.Time; proxy of <Swig Object of type 'Time *' at 0x000001ED4F866090> >]
>>> r[1].year
2021
>>> r[1].month
12
如果您想为 Time
自定义 SWIG 包装器的显示,使其更易于阅读,您可以使用以下方法扩展 Time 对象:
%module test
%{
// Added to support the __repr__ implementation
#include <string>
#include <sstream>
#include "DeviceInterface.h"
%}
%include <stdint.i>
%include <std_string.i> // SWIG support for std::string.
%typemap(in,numinputs=0) Time& %{
= new Time;
%}
%typemap(argout) Time& (PyObject* tmp) %{
tmp = SWIG_NewPointerObj(, _descriptor, SWIG_POINTER_OWN);
$result = SWIG_Python_AppendOutput($result, tmp);
%}
// Extend time to suport Python's __repr__.
// It must return a string representing how to display the object in Python.
%extend Time {
std::string __repr__()
{
std::ostringstream ss;
ss << "Time(year=" << $self->year << ", month=" << (unsigned)$self->month
<< ", day=" << (unsigned)$self->day << ", hour=" << (unsigned)$self->hour
<< ", minute=" << (unsigned)$self->minute << ", second=" << (unsigned)$self->second << ")";
return ss.str();
}
}
%include "DeviceInterface.h"
演示:
>>> import test
>>> d=test.DeviceInterface()
>>> r=d.getTime()
>>> r
[0, Time(year=2021, month=12, day=30, hour=9, minute=47, second=30)]
老实说,我阅读并重读了本网站上有关 struct 主题的很多 post。但是我需要你的帮助。
我有 C 风格的结构
struct Time
{
uint16_t year; // year with four digits like 2016
uint8_t month; // 1 .. 12
uint8_t day; // 1 .. 31
uint8_t hour; // 0 .. 23, 24 hour representation
uint8_t minute; // 0 .. 59
uint8_t second; // 0 .. 59
};
和class带有成员函数,其实现在DLL中。
class DeviceInterface {
virtual uint32_t getTime(Time& time) = 0;
};
其中 uint32_t 值为状态代码。
这里是自动生成的 SWIG C++ 代码:
SWIGINTERN PyObject *_wrap_getTime(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *resultobj = 0;
DeviceInterface *arg1 = (DeviceInterface *) 0 ;
Time *arg2 = 0 ;
void *argp1 = 0 ;
int res1 = 0 ;
void *argp2 = 0 ;
int res2 = 0 ;
PyObject *swig_obj[2] ;
uint32_t result;
if (!SWIG_Python_UnpackTuple(args, "getTime", 2, 2, swig_obj)) SWIG_fail;
res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_DeviceInterface, 0 | 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "getTime" "', argument " "1"" of type '" "DeviceInterface *""'");
}
arg1 = reinterpret_cast< DeviceInterface * >(argp1);
res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_Time, 0 );
if (!SWIG_IsOK(res2)) {
SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "getTime" "', argument " "2"" of type '" "Time &""'");
}
if (!argp2) {
SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "getTime" "', argument " "2"" of type '" "Time &""'");
}
arg2 = reinterpret_cast< Time * >(argp2);
result = (uint32_t)(arg1)->getTime(*arg2);
resultobj = SWIG_From_unsigned_SS_int(static_cast< unsigned int >(result));
return resultobj;
fail:
return NULL;
}
从上面的代码中我看不到什么时间值,即 arg2 变量,不知何故被返回。那么我需要在 SWIG 接口文件中编写什么来获取状态代码和 time?
您可以编写一个类型映射来附加 Time
输出参数。 SWIG 为可以根据需要通过 SWIG_NewPointerObj()
生成的结构生成代理。完整示例如下:
DeviceInterface.h(最小实现)
#include <stdint.h>
struct Time
{
uint16_t year; // year with four digits like 2016
uint8_t month; // 1 .. 12
uint8_t day; // 1 .. 31
uint8_t hour; // 0 .. 23, 24 hour representation
uint8_t minute; // 0 .. 59
uint8_t second; // 0 .. 59
};
class DeviceInterface {
public:
virtual uint32_t getTime(Time& time) {
time.year = 2021;
time.month = 12;
time.day = 30;
time.hour = 9;
time.minute = 47;
time.second = 30;
return 0;
}
};
test.i
%module test
%{
#include "DeviceInterface.h"
%}
%include <stdint.i>
// Do not require an input parameter for Time.
// Instead, SWIG will allocate one.
%typemap(in,numinputs=0) Time& %{
= new Time;
%}
// After calling the function, process Time as an output.
// Convert the allocated pointer to a SWIG Python wrapper
// and pass ownership to Python. Python will free the object
// when it goes out of scope.
%typemap(argout) Time& (PyObject* tmp) %{
// Convert C pointer to SWIG Python wrapper
tmp = SWIG_NewPointerObj(, _descriptor, SWIG_POINTER_OWN);
// Append to existing uint32_t return value
$result = SWIG_Python_AppendOutput($result, tmp);
%}
%include "DeviceInterface.h"
演示:
>>> import test
>>> d=test.DeviceInterface()
>>> r=d.getTime()
>>> r
[0, <test.Time; proxy of <Swig Object of type 'Time *' at 0x000001ED4F866090> >]
>>> r[1].year
2021
>>> r[1].month
12
如果您想为 Time
自定义 SWIG 包装器的显示,使其更易于阅读,您可以使用以下方法扩展 Time 对象:
%module test
%{
// Added to support the __repr__ implementation
#include <string>
#include <sstream>
#include "DeviceInterface.h"
%}
%include <stdint.i>
%include <std_string.i> // SWIG support for std::string.
%typemap(in,numinputs=0) Time& %{
= new Time;
%}
%typemap(argout) Time& (PyObject* tmp) %{
tmp = SWIG_NewPointerObj(, _descriptor, SWIG_POINTER_OWN);
$result = SWIG_Python_AppendOutput($result, tmp);
%}
// Extend time to suport Python's __repr__.
// It must return a string representing how to display the object in Python.
%extend Time {
std::string __repr__()
{
std::ostringstream ss;
ss << "Time(year=" << $self->year << ", month=" << (unsigned)$self->month
<< ", day=" << (unsigned)$self->day << ", hour=" << (unsigned)$self->hour
<< ", minute=" << (unsigned)$self->minute << ", second=" << (unsigned)$self->second << ")";
return ss.str();
}
}
%include "DeviceInterface.h"
演示:
>>> import test
>>> d=test.DeviceInterface()
>>> r=d.getTime()
>>> r
[0, Time(year=2021, month=12, day=30, hour=9, minute=47, second=30)]