C语言 使用Perl XS结构体



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

其中$resultparse C函数的结果

首先,必须为结果类选择一个名称。从现在开始,我将简单地使用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导出它。

可以使用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));

相关内容

  • 没有找到相关文章

最新更新