3

我是 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  

如何更改上面的代码以parse_xs像这样在 Perl 代码中运行

my $result = parse_xs();

print $result->data; # will print the data field from the struct.

其中$resultparseC 函数的结果。

4

2 回答 2

6

首先,您必须为结果类选择一个名称。从现在开始我会简单地使用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函数为结果结构分配内存。返回指向堆栈上结构的指针不起作用。我还添加了一些小的优化,例如传递字符串 asSV并使用SvPV.

为了释放分配的内存,你必须实现一个析构函数(DESTROY在 Perl 中命名):

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.

于 2015-03-12T14:35:40.483 回答
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));
于 2014-08-06T07:06:00.023 回答