如何为双指针结构参数应用SWIG类型图 [英] How to apply a SWIG typemap for a double pointer struct argument

查看:117
本文介绍了如何为双指针结构参数应用SWIG类型图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个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_tracksdoes. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆