这(我希望)是一个非常简单的问题,但是尽管做了一些阅读(我对SWIG的新版本,以及相当绿色的C版本),我还是无法做出& #34;连接"在我脑海里。
我有一个库中的函数(遗留代码,不想编辑):
extern int myfunction(char *infile, char *maskfile, int check, float *median, char *msg)
我的目标是使用SWIG在Python中创建一个包装器。
C函数更改median
和msg
变量的值。当返回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
太小,我可能会得到缓冲区溢出。
我希望这很清楚 - 很高兴为进一步的讨论添加评论。
答案 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()
不应与char
或char *
类型一起使用。
我认为你的代码没有正确地创建以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;也许是必要的。