SWIG:需要可变字符串类型映射帮助

时间:2016-03-04 21:40:09

标签: python c swig

这(我希望)是一个非常简单的问题,但是尽管做了一些阅读(我对SWIG的新版本,以及相当绿色的C版本),我还是无法做出& #34;连接"在我脑海里。

我有一个库中的函数(遗留代码,不想编辑):

extern int myfunction(char *infile, char *maskfile, int check, float *median, char *msg)

我的目标是使用SWIG在Python中创建一个包装器。

C函数更改medianmsg变量的值。当返回int != 0时,msg arg中会出现一些错误信息。返回int == 0,然后median变量将包含一个值为myfunction的浮点值。

这通常在返回值为0时运行正常。我使用%array_functions%pointer_functions创建需要传递的指针,根据此.i文件:

%module test
%include "cpointer.i"
%include "carrays.i"
%{
 #include <stdint.h>
%}

extern int myfunction(char *infile, char *maskfile, int check, float *median, char *msg)

%pointer_functions(float, floatp);
%pointer_functions(char, charp);
%array_functions(char, charArray);

在swiging,编译和链接之后,我可以在python中调用函数:

import test
errmsg_buffer = 1024
_infile = 'test2.dat'
infile  = imstat.new_charArray(len(_infile))
for i in xrange(len(_infile)):
    imstat.charArray_setitem(infile,i,_infile[i])
maskfile = imstat.new_charArray(1)
imstat.charArray_setitem(maskfile,0,'')
check = 0
med = imstat.new_floatp()
errmsg = imstat.new_charArray(errmsg_buffer)

out = test.myfunction(infile,maskfile,check,med,errmsg)
median = test.floatp_value(med)

这有时会起作用,但通常不行 - 我得到了很多段错误,这些段错误通常通过更改errmsg_buffer长度来修复(显然不是一个有用的修复!)。更改msg字符串的C代码是:

(void)sprintf(errmsg,"file not found");

我的主要问题是正确处理msg字符串,我怀疑这会导致段错误(可能是由于new_charArray的错误实现?)。

最好的方法是什么?

我可以向.i添加一些内容,将char *msg转换为python str吗?

这可以在没有&#34;预初始化&#34;与new_CharArray?如果errmsg_buffer太小,我可能会得到缓冲区溢出。

我希望这很清楚 - 很高兴为进一步的讨论添加评论。

2 个答案:

答案 0 :(得分:1)

使用SWIG可以大大简化您的包装器。试试这个SWIG接口文件(详见下文):

%module test
%include "typemaps.i"
%include "cstring.i"
%apply float *OUTPUT { float *median };
%cstring_bounded_output(char *msg, 1024);
extern int myfunction(char *infile, char *maskfile, int check, float *median, char *msg);

然后,从python中,按以下方式使用该模块:

import test
infile = 'test2.dat'
maskfile = ''
check = 0
out, median, errmsg = test.myfunction(infile,maskfile,check)
if out == 0: print(errmsg)
...

但是,从你写的内容来看,我不清楚为什么你的方法会出现段错误。

详细信息

  • typemaps.i文件包含float *OUTPUT类型映射,然后将其应用于float *median参数,并将其从参数转换为float输出值。有关详细信息,请参阅argument handling上的SWIG文档。

  • cstrings.i文件包含用于处理C字符串的SWIG宏。在这里,我使用了%cstring_bounded_output宏。这将创建一个给定大小为1024的char *缓冲区,并自动将其作为char *msg的参数传递。然后,函数完成后的内容将转换为python字符串并附加到输出。有关详细信息,请参阅here

  • SWIG默认处理前两个char *参数,即将python字符串转换为适当的char *并传递这些参数。请注意,这些参数的传递char *是不可变的,即,如果您的myfunction尝试修改这些参数,则会发生错误。了解SWIG如何处理C字符串here

  • 因此,您的包装myfunction然后如上所示使用,并在python中具有以下签名: myfunction(infile, maskfile, check) -> (out, median, msg)

编辑:

关于carrays.i州的SWIG文档:

  

注意: %array_functions()%array_class()不应与charchar *类型一起使用。

我认为你的代码没有正确地创建以NULL结尾的C char *,所以这可能会导致段错误。

答案 1 :(得分:0)

我没有深入学习SWIG。但我尝试给你一些建议。 1。   如果您的程序修改输入参数或使用它来返回数据,请考虑使用SWIG Library章节中描述的cstring.i库文件。 数据被复制到新的Python字符串中并返回。   如果您的程序需要使用二进制数据,则可以使用类型映射将Python字符串扩展为指针/长度参数对。幸运的是,已经定义了这样的类型图。就这样做:

    %apply (char *STRING, int LENGTH) { (char *data, int size) };
   ...
   int parity(char *data, int size, int initial);

的Python:

parity("e\x09ffss\x00\x00\x01\nx", 0)

如果需要返回二进制数据,可以使用cstring.i库文件。 cdata.i库也可用于从任意指针获取额外的二进制数据。

2.我认为&#34;预先初始化&#34;也许是必要的。