Python 如何为双指针结构参数应用SWIG类型映射
我有一个API,我正试图使用SWIG包装它,这样我就可以从python调用底层的C库 我遇到了一个特殊的API fn:Python 如何为双指针结构参数应用SWIG类型映射,python,c,pointers,swig,Python,C,Pointers,Swig,我有一个API,我正试图使用SWIG包装它,这样我就可以从python调用底层的C库 我遇到了一个特殊的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 *li
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
数据结构的双指针
所有的单指针都工作正常
这是唯一一个双指针指向track\u t
所有其他的都只有一个指针,例如
void print_hash_tracks(const track_t *hash_tracks, const cfg_t *cfg,
enum TRKTYPE trktype);
我很确定我需要在我的SWIG接口文件(interface.I)中创建一个类型映射,但是我发现SWIG文档无法穿透
我想我需要做的是创建一个类型映射,每当它看到track\u t**
类型时,它就会获取一个track\u t*
并将其转换为地址,类似于:
/* provide typemap to handle instances of track_t** parameters */
%typemap(in) track_t** (track_t *tracks) {
$1 = &tracks;
}
但当我跑步时,我只是遇到了分段错误:
tracks = g3.track_t()
g3.update_tracks(tracks, pdw_frame, rdw_frame, lib, lib_meta, cfg)
在python方面
我觉得我几乎解决了这个问题,但不能完全正确地获得typemap规范,同时努力理解相关文档
柔印-如果你在那里-也许你能对此有所了解,你似乎是这方面的专家
更新-m7ython(太棒了!另一位SWIG专家在SO上)
C语言中的用法非常简单
声明并初始化指向NULL的跟踪指针:
track_t *hash_tracks = NULL;
然后:
因此指向track\u t
的指针的地址作为参数传递给update\u tracks()
。update\u tracks()
fn为放入hash\u tracks
的数据处理所有必要的malloc,即track\u t
结构的哈希表
所有其他参数都是单指针,我可以创建和填充它们,而python方面没有任何问题
track\u t
是一个包含一组整数、浮点数、字符*等的结构
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库)<代码>哈希轨道指向哈希表中的第一个轨道。在update_tracks()
fn track_t结构体中,可以从哈希表中添加/删除结构,以便指向第一个轨迹的指针可能会更改,即hash_tracks()调用update_tracks()
后可能指向其他对象,因此需要将指针传递给指针
换句话说,track\u t**
arg、phash\u tracks
被用作输入和输出类型arg,因此是指向指针的指针。所有其他参数都只是输入,它们不会更改,因此可以作为单指针传入
我使用以下C fn尝试了“helper fn”路由:
track_t** make_phash_tracks(void)
{
track_t **phash_tracks;
phash_tracks = calloc(1, sizeof(track_t*));
return phash_tracks;
}
calloc的使用应确保*phash_轨道为空
这是编译和包装的,没有错误,但当我从python端使用它时,它会出错,例如
phash_tracks = g3.make_phash_tracks()
g3.update_tracks(phash_tracks, pdw_frame, rdw_frame, lib, lib_meta, cfg)
在调用update\u tracks
之前检查phash\u tracks
var,给出:
(Pdb) p phash_tracks
<Swig Object of type 'track_t **' at 0x7fb9e37c9030>
(Pdb)p相轨道
编辑:好的,我想我现在明白了更新曲目的作用了。您似乎可以通过两种方式使用该函数。如果将指针传递给NULL
指针,则可以更新现有磁道
,也可以创建磁道
。我不确定在SWIG中处理这两种情况的最优雅的方法是什么(或者这是否是一个问题),但这里有一些选择
1. <代码>相位跟踪
是一个输出参数
首先,您必须将*phash_tracks
作为返回值传递回Python,并以如下形式使用函数
>>> int_res, tracks = g3.update_tracks(tracks, pdw_frame, rdw_frame, lib, lib_meta, cfg)
或
这是通过以下“argout”类型映射实现的:
也许您不希望Python拥有跟踪*
,然后用0
替换SWIG\u指针
2.通过空的phash_轨道
如果您只想使用update_tracks
功能来创建曲目
,则基本上可以执行您已经在执行的操作。使用下面的“in”类型映射,并使用上面第二个示例中的函数(不带tracks
参数)
3. <代码>相位跟踪
作为输入(和输出)参数
如果您想使用update\u tracks
来更新现有的tracks
,您应该能够使用我之前建议的“in”类型映射,并像第一个示例一样使用Python中的函数(包括tracks
参数)
请注意,Python不承认它的跟踪
,这一点很重要
%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;
}
4.同时启用上述(2)和(3)
如果您可以让swig通过一个包装的NULL
轨道*
,那么基本上也可以使用版本(3)来创建轨道。我不确定SWIG是否允许这样做,但也许它允许。尝试使用辅助函数:
tracks_t* empty_tracks() { return NULL; }
或者,您可以沿以下行修改“in”类型映射,尝试将提供的参数转换为track\t*
并传递其地址,或者传递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中,只需传递其他内容来创建曲目
:
>>> int_res, tracks = g3.update_tracks(0, pdw_frame, rdw_frame, lib, lib_meta, cfg)
我不知道SWIG,但是看看函数调用,你确定你正确地传递了双指针吗?似乎您传递的不是磁道的地址,而是值本身。TBH如果您不知道SWIG,则可能无法提供太多信息。typemap正在尝试将轨迹指针转换为双指针。它被合并到自动生成的包装器代码中,我相信您可以用C语言给出一个示例,说明如何使用update\u tracks
?当前,您的类型映射将轨迹**
传递给未初始化的轨迹*
,并且在函数完成后不使用轨迹**
。如果你能得到你的手
%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;
}
tracks_t* empty_tracks() { return NULL; }
%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;
}
>>> int_res, tracks = g3.update_tracks(0, pdw_frame, rdw_frame, lib, lib_meta, cfg)