我是Perl XS的新手,我正在尝试将C函数转换为Perl子例程。
我有以下C函数
void parse(struct parser *result, const char *string, size_t len);
其中parse
函数接受指向struct parser
的指针,字符串和字符串的长度。 struct parser
定义如下:
struct parser {
char *data;
long a;
long b;
long c;
};
该函数将其结果存储在result
参数中。
我想将此功能转换为Perl XS。我正在做的是这样的:
struct parser *result
parse_xs (string)
const char* string
PREINIT:
long len = strlen(string);
CODE:
struct parser par;
parse(&par,s,len);
RETVAL = par;
OUTPUT:
RETVAL
如何更改上述代码以在此类
的Perl代码中运行parse_xs
my $result = parse_xs();
print $result->data; # will print the data field from the struct.
其中$result
是parse
C函数的结果。
答案 0 :(得分:5)
首先,您必须为结果类选择一个名称。我从现在开始只使用ParseResult
。
您还需要一个typemap
文件。要将C结构映射到Perl类,请使用内置的T_PTROBJ
:
TYPEMAP
ParseResult T_PTROBJ
然后将typedef和ParseResult
包添加到您的XS代码中:
typedef struct parser *ParseResult;
MODULE = YourModule PACKAGE = ParseResult
确保typedef出现在所有MODULE
部分之前。现在,您可以为parse_xs
函数添加XSUB(您可能只需将其命名为parse
):
ParseResult
parse_xs(string)
SV *string
PREINIT:
const char *c_string;
STRLEN len;
CODE:
Newx(RETVAL, 1, struct parser);
c_string = SvPV(string, len);
parse(RETVAL, c_string, len);
OUTPUT:
RETVAL
请注意,我使用Perl的Newx
函数为结果结构分配内存。返回指向堆栈上的结构的指针不起作用。我还添加了一些小的优化,例如将字符串作为SV
传递,并使用SvPV
获取内容和长度。
为了释放分配的内存,你必须实现一个析构函数(在Perl中名为DESTROY
):
void
DESTROY(result)
ParseResult result
CODE:
/* Possibly free data in result here. */
Safefree(result);
您的结果结构可能指向其他已分配的内存。在致电Safefree
之前,请务必释放此内存。
然后你可以写这样的访问器:
const char *
data(result)
ParseResult result
CODE:
RETVAL = result->data;
OUTPUT:
RETVAL
现在你必须为你的班级写一个Perl模块。添加名为ParseResult.pm
的文件,其中包含以下内容:
package ParseResult;
use strict;
use warnings;
use XSLoader;
our $VERSION = '0.01';
XSLoader::load('ParseResult', $VERSION);
1;
然后可以像这样使用新的基于XS的类:
use ParseResult;
my $result = ParseResult::parse_xs('input');
print $result->data, "\n";
请注意,我使用parse_xs
的完全限定名称。如果您想在没有类名的情况下调用它,则必须从ParseResult.pm
中导出它。
答案 1 :(得分:2)
您可以将C结构用作Perl对象。 请参阅以下页面(此页面是日语,但您可能了解源代码)。
http://d.hatena.ne.jp/perlcodesample/20140807/1407291461
// creat struct as pointer
Point* point = (Point*)malloc(sizeof(Point));
point->x = x;
point->y = y;
// Convert pointer to size_t
size_t point_iv = PTR2IV(point);
// Convert size_t to SV*
SV* point_sv = sv_2mortal(newSViv(point_iv));
// Create reference to SV*
SV* point_svrv = sv_2mortal(newRV_inc(point_sv));
// Create Object
SV* point_obj = sv_bless(point_svrv, gv_stashpv(class_name, 1));