【问题标题】:Perl API Inline C: How to get get a substr of a Perl byte string by reference without copying that stringPerl API Inline C:如何通过引用获取 Perl 字节字符串的子字符串而不复制该字符串
【发布时间】:2018-08-02 04:49:08
【问题描述】:

大家好,希望能在这里遇到一些字节串专家。 我猜 SvPVbyte 会发挥作用,但如何?

我的问题。 我已经在 Inline:C 中使用 Perl 成功地解析了 Perl 数组 XYZ(在数组的哈希中),例如索引 6789:

$testn=pnp($lengthofXYZ,\@{$XYZ{$_}});

内联 C:

int pnp ( int n, SV *vertx)
AV *arrayx;
double val_of_interest;
arrayx = (AV *)SvRV( vertx );
SV **yi;
yi = av_fetch( arrayx, 6789, 0 );
val_of_interest = SvNV( *yi );
return calculation_with_val_of_interest

这非常有效。但是假设我在 Perl 中有一个很长的字节字符串(大约 10-50MB) $xyz="\x09\x07\x44\xaa......

现在我想传递对这个 SV 的引用,并在 C 部分中以 9 个字节的步长(类似 substr)遍历这个字符串,而不是将其完全复制到自己的 C 数组中。

步行部分: 前 4 个字节应与参考 4 字节值 ABC 进行检查,该值也应在函数调用中。如有必要,我可以在此之前解压缩“N”这个搜索短语并使用整数调用函数。 如果位置 0 没有成功跳转/增加 9 个字节,如果成功我会将找到的位置作为返回。

非常感谢。

【问题讨论】:

    标签: perl byte inline substr perlapi


    【解决方案1】:
    #include <stdint.h>
    #include <string.h>
    
    void foo(SV* sv) {
        STRLEN len;
        const char *buf = SvPVbyte(sv, len);
    
        if (len < 4) {
            /* ... Error ... */
        }
    
        uint32_t sig =
            ((unsigned char)(buf[0]) << 24) |
            ((unsigned char)(buf[1]) << 16) |
            ((unsigned char)(buf[2]) <<  8) |
            ((unsigned char)(buf[3]) <<  0);
    
        buf += 4;
        len -= 4;
        if (sig != ...) {
            /* ... Error ... */
        }
    
        while (len >= 9) {
            char block[9];
            memcpy(block, buf, 9);
            buf += 9;
            len -= 9;
    
            /* ... Use block ... */
        }
    
        if (len > 0) {
            /* ... Error ... */
        }
    }
    

    [这是对cmets中问题的回答]

    • 永远不要使用use bytes;。 “强烈建议不要将此模块用于调试目的以外的任何用途。” (而且它实际上对调试没有用处。Devel::Peek 更有用。)
    • 绝对没有理由在这里使用our
    • int 对于返回值来说可能太小了。
    • 它不起作用,因为您正在搜索引用的字符串化。
    • 事实上,没有必要创建引用。

    use strict;
    use warnings qw( all );
    
    use Inline C => <<'__EOS__';
    
    SV* find_first_pos_of_43h_in_byte_string(SV* sv) {
        STRLEN len;
        const char *p_start = SvPVbyte(sv, len);
        const char *p = p_start;
        const char *p_end = p_start + len;
        for (; p < p_end; ++p) {
            if (*p == 0x43)
                return newSVuv(p - p_start);
        }
    
        return newSViv(-1);
    }
    
    __EOS__
    
    my $buf = "\x00\x00\x43\x01\x01\x01";
    my $pos = find_first_pos_of_43h_in_byte_string($buf);
    

    当然,你可以简单地使用

    use strict;
    use warnings qw( all );
    
    my $buf = "\x00\x00\x43\x01\x01\x01";
    my $pos = index($buf, chr(67));
    

    【讨论】:

    • 亲爱的池上,现在我是第一次阅读这些台词。星期六,我的儿子(8 岁)在操场上发生了非常严重的事故,我们住院了。我看到它有效(是的!!!9)现在将调整它以适应 9 字节步骤(您已经显示了“解包”),并检查通过的 4 字节搜索值位置。非常感谢您的耐心等待。对你表示热烈的感谢。格茨
    • Ikegami 我必须在字符串中(在字符串的散列中)传递引用和要搜索的 4 字节值。但我一个人就能做到……希望如此。
    • 不知道“字符串中的引用”是什么意思,但绝对没有理由传递引用。哈希元素(例如$hash{foo})只是一个标量,所以只需传递它
    • 再一次,只需使用index
    • 我使用了“使用字节”,因为我认为 length+substr 命令有时可能会失败,因为我的二进制字符串中有错误的 utf8 解释。我不能使用索引,因为我有严格的 9 字节步骤来搜索 4 字节的值,并且由于字符串很大,我会让你的解决方案适应二进制搜索。 (这是完美地使用数组而不是字符串的 substr 运行(也在 C 中),但需要大量内存)
    猜你喜欢
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    • 2011-12-27
    • 2014-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多