如何为双指针结构参数应用SWIG类型图 [英] How to apply a SWIG typemap for a double pointer struct argument
问题描述
我有一个API,正在尝试使用SWIG包装,以便可以从python调用基础C库.
I have an API that I am trying to wrap using SWIG such that I can call the underlying C library from python.
我陷入了特定的API fn:
I have got stuck with a particular API fn:
int update_tracks(track_t **phash_tracks,
const pdws_t *pdw_frame,
const rdws_t *rdw_frame,
lib_t *lib,
lib_meta_t *lib_meta,
const cfg_t *cfg);
它是我无法处理的指向track_t
数据结构的双指针.
Its the double pointer to track_t
data structure that I can't handle.
所有单个指针都可以正常工作.
All the single pointers work fine.
这是唯一具有指向track_t
所有其他人只有一个指针,例如
All the others only have a single pointer, e.g.
void print_hash_tracks(const track_t *hash_tracks, const cfg_t *cfg,
enum TRKTYPE trktype);
我很确定我需要在SWIG接口文件(interface.i)中创建一个类型图,但是我发现SWIG文档不可穿透.
I'm pretty sure I need to make a typemap in my SWIG interface file (interface.i) but I am finding the SWIG docs impenetrable.
我想我需要做的是创建一个类型映射,只要它看到track_t**
类型,就需要一个track_t*
并将其转换为其地址,例如:
What I think I need to do is create a typemap that whenever it sees the track_t**
type, it takes a track_t*
and converts it to its address, something like:
/* provide typemap to handle instances of track_t** parameters */
%typemap(in) track_t** (track_t *tracks) {
$1 = &tracks;
}
但是我在运行时遇到分段错误:
but I'm just getting segmentation faults when I run:
tracks = g3.track_t()
g3.update_tracks(tracks, pdw_frame, rdw_frame, lib, lib_meta, cfg)
在python端.
我觉得我几乎解决了这个问题,但是不能完全正确地定义类型映射规范,同时又在努力理解相关文档.
I feel like I've almost solved this but can't quite get the typemap specification right and at the same time struggling to understand the relevant documentation.
flexo-如果您在外面-也许您可以对此有所了解,那么您似乎是该领域的SO专家.
flexo - if you're out there - maybe you can shed some light on this, you seem to be the SO expert in this area..
更新-m7ython(非常棒!另一位SWIG SO专家)
UPDATE - m7ython (brilliant! another SWIG expert on SO)
在C语言中的用法相当简单
Usage in C is pretty straigthforward
声明并初始化一个指向NULL的track_t指针:
declare and initialise a track_t pointer to NULL:
track_t *hash_tracks = NULL;
然后:
update_tracks(&hash_tracks, &pdw_frame, &rdw_frame,
&lib, &lib_meta, &cfg);
因此,指向track_t
的指针的地址作为arg传递给update_tracks()
. update_tracks()
fn处理要放入hash_tracks
中的数据的所有必要的malloc,即track_t
结构的哈希表
So the address of the pointer to track_t
is passed as an arg to update_tracks()
. The update_tracks()
fn takes care of all the necessary mallocs for the data that gets put into hash_tracks
, i.e. the hash table of track_t
structs
所有其他args都是单指针,我可以在python端创建和填充它们而不会出现问题.
All the other args are single pointers and I can create and populate them with no issues on the python side.
track_t
是包含一堆int,float,char *等的结构.
track_t
is a struct containing a bunch of ints, floats, char* etc. e.g.
typedef struct
{
/* make struct hashable */
UT_hash_handle hh;
int id;
...
char name[MAX_BUF];
...
} track_t;
track_t arg是track_t**
而不只是track_t*
的原因是因为hash_tracks
是指向哈希表的指针(使用UTHash库). hash_tracks
指向哈希表中的第一个track_t.在update_tracks()
的主体中,可以从哈希表中添加/删除track_t结构,以使指向第一个track_t的指针可以更改,即,在调用update_tracks()
之后,hash_tracks
可以指向其他内容,因此将指针传递给指针的原因.
The reason that the track_t arg is a track_t**
and not just a track_t*
is because hash_tracks
is a pointer to a hash table (using the UTHash library). hash_tracks
points to the 1st track_t in the hash table. In the body of the update_tracks()
fn track_t structs can be added/removed from the hash table, such that the pointer to the 1st track_t may change, i.e. hash_tracks
may point to something else after the call to update_tracks()
, hence the reason for passing a pointer to the pointer.
换句话说,track_t**
arg,phash_tracks
既用作输入类型,也用作输出类型arg,因此是指向指针的指针.所有其他args只是输入,它们不会改变,因此可以作为单个指针传递.
In other words, the track_t**
arg, phash_tracks
is being used both as an input and output type arg, hence the pointer to a pointer. All the other args are simply inputs, they don't change so they can be passed in as single pointers.
我尝试使用以下C fn进行"helper fn"路由:
I attempted the 'helper fn' route with the following C fn:
track_t** make_phash_tracks(void)
{
track_t **phash_tracks;
phash_tracks = calloc(1, sizeof(track_t*));
return phash_tracks;
}
使用calloc应该确保* phash_tracks为NULL
the use of calloc should ensure that *phash_tracks is NULL
这个经过编译和包装的程序没有错误,但是当我从python端使用它时,它会出现段错误,例如
this compiled and wrapped with no errors, but when I used it from the python side it segfaulted, e.g.
phash_tracks = g3.make_phash_tracks()
g3.update_tracks(phash_tracks, pdw_frame, rdw_frame, lib, lib_meta, cfg)
在调用update_tracks
之前检查phash_tracks
变量给出了:
checking the phash_tracks
var just prior to calling update_tracks
gave:
(Pdb) p phash_tracks
<Swig Object of type 'track_t **' at 0x7fb9e37c9030>
推荐答案
好的,我想我现在了解update_tracks
的作用.看来您可以通过两种方式使用该功能.如果将指针传递给NULL
指针,则更新现有的tracks
或创建tracks
.我不确定在SWIG中处理这两种情况的最佳方法(或者甚至是一个问题),但是这里有一些选择.
Ok, I think I now understand what update_tracks
does. It seems you can use the function in two ways. Either to update existing tracks
, or to create tracks
if you pass a pointer to a NULL
pointer. I am not sure about the most elegant way to handle both cases in SWIG (or if this is even a problem), but here are some options.
首先,您必须将*phash_tracks
作为返回值传递回Python,并以某种形式使用该函数
First, you must pass *phash_tracks
back to Python as a return value, and use the function in some form like
>>> int_res, tracks = g3.update_tracks(tracks, pdw_frame, rdw_frame, lib, lib_meta, cfg)
或
>>> int_res, tracks = g3.update_tracks(pdw_frame, rdw_frame, lib, lib_meta, cfg)
这是通过以下"argout"类型映射完成的:
This is accomplished by the following "argout" typemap:
%typemap(argout) track_t **phash_tracks {
%append_output(SWIG_NewPointerObj(%as_voidptr(*$1), $*1_descriptor, SWIG_POINTER_OWN));
}
也许您不希望Python拥有track_t*
的所有权,然后将SWIG_POINTER_OWN
替换为0
.
Maybe you don't want Python to take ownership of the track_t*
, then replace SWIG_POINTER_OWN
by 0
.
如果只想使用update_tracks
函数创建 tracks
,则基本上可以执行您已经在做的事情.使用下面的"in"类型映射,并像上面的第二个示例一样使用该函数(不带tracks
参数).
If you only want to use the update_tracks
function to create tracks
, you can do essentially what you are already doing. Use the following "in" typemap, and use the function as in the second example above (without the tracks
parameter).
%typemap(in, numinputs=0) track_t **phash_tracks (track_t *tracks) {
tracks = NULL;
$1 = &tracks;
}
3. phash_tracks
作为输入(和输出)参数
如果您想使用update_tracks
更新现有 tracks
,则应该能够使用我之前建议的"in"类型映射,并像在第一个中那样使用Python中的函数示例(包括tracks
参数).
3. phash_tracks
as an input (and output) argument
If you want to use update_tracks
to update existing tracks
, you should be able to use the "in" typemap I suggested before, and use the function from Python as in the first example (including the tracks
parameter).
%typemap(in) track_t **phash_tracks (track_t *tracks) {
if ((SWIG_ConvertPtr($input, (void **) &tracks, $*1_descriptor, SWIG_POINTER_EXCEPTION | SWIG_POINTER_DISOWN)) == -1)
return NULL;
$1 = &tracks;
}
请注意,Python放弃其tracks_t*
非常重要.
Note that it is important that Python disowns its tracks_t*
.
如果您可以大吃一惊,通过包装的NULL
tracks_t*
,则基本上也可以使用版本(3)来创建 tracks
.我不确定SWIG是否允许这样做-但也许可以.尝试使用辅助功能:
You could basically use version (3) also to create tracks
, if you could get swig to pass a wrapped NULL
tracks_t*
. I am not sure if SWIG allows this -- but maybe it does. Try using a helper function:
tracks_t* empty_tracks() { return NULL; }
或者,您可以沿着以下几行修改"in"类型映射,尝试将提供的参数转换为track_t*
并传递其地址,或者传递NULL
track_t*
的地址.
Alternatively, you can modify the "in" typemap along the following lines, attempting to convert the provided argument to a track_t*
and passing its address, or alternatively passing the address of a NULL
track_t*
.
%typemap(in) track_t **phash_tracks (track_t *tracks) {
// Alternatively, check if $input is a 0 integer `PyObject`...
if ((SWIG_ConvertPtr($input, (void **) &tracks, $*1_descriptor, SWIG_POINTER_DISOWN)) == -1)
tracks = NULL;
$1 = &tracks;
}
然后,通过Python,只需传递其他内容即可创建tracks
:
Then, from Python, just pass something else to create tracks
:
>>> int_res, tracks = g3.update_tracks(0, pdw_frame, rdw_frame, lib, lib_meta, cfg)
这篇关于如何为双指针结构参数应用SWIG类型图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!