在Perl XS中使用struct

smi*_*ith 3 c perl xs

我是Perl XS的新手,我正在尝试将C函数转换为Perl子例程.

我有以下C函数

void parse(struct parser *result, const char *string, size_t len);
Run Code Online (Sandbox Code Playgroud)

其中parse函数接受的指针struct parser,一个字符串,该字符串的长度.struct parser定义如下:

struct parser {
    char *data;
    long  a;
    long  b;
    long  c;
};
Run Code Online (Sandbox Code Playgroud)

该函数将其结果存储在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  
Run Code Online (Sandbox Code Playgroud)

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

my $result = parse_xs();

print $result->data; # will print the data field from the struct.
Run Code Online (Sandbox Code Playgroud)

C函数$result的结果在哪里parse.

nwe*_*hof 6

首先,您必须为结果类选择一个名称.我ParseResult将从现在开始使用.

你还需要一个typemap文件.要将C结构映射到Perl类,请使用内置的T_PTROBJ:

TYPEMAP
ParseResult     T_PTROBJ
Run Code Online (Sandbox Code Playgroud)

然后将typedef和ParseResult包添加到XS代码中:

typedef struct parser *ParseResult;

MODULE = YourModule  PACKAGE = ParseResult
Run Code Online (Sandbox Code Playgroud)

确保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
Run Code Online (Sandbox Code Playgroud)

请注意,我使用Perl的Newx函数为结果struct分配内存.返回指向堆栈上的结构的指针不起作用.我还添加了一些小的优化,比如传递字符串SV并获取内容和长度SvPV.

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

void
DESTROY(result)
    ParseResult result
CODE:
    /* Possibly free data in result here. */
    Safefree(result);
Run Code Online (Sandbox Code Playgroud)

结果struct可能指向其他已分配的内存.请务必在通话前释放此内存Safefree.

然后你可以写这样的访问器:

const char *
data(result)
    ParseResult result
CODE:
    RETVAL = result->data;
OUTPUT:
    RETVAL
Run Code Online (Sandbox Code Playgroud)

现在你必须为你的类编写一个Perl模块.添加以ParseResult.pm下列内容命名的文件:

package ParseResult;
use strict;
use warnings;

use XSLoader;

our $VERSION = '0.01';
XSLoader::load('ParseResult', $VERSION);

1;
Run Code Online (Sandbox Code Playgroud)

然后可以像这样使用新的基于XS的类:

use ParseResult;

my $result = ParseResult::parse_xs('input');
print $result->data, "\n";
Run Code Online (Sandbox Code Playgroud)

请注意,我使用完全限定名称parse_xs.如果要在没有类名的情况下调用它,则必须从中导出ParseResult.pm.