Perl API Inline C: как получить подстроку строки байта Perl по ссылке, не копируя эту строку

Здравствуйте, сообщество. Надеюсь, я смогу встретиться здесь с некоторыми экспертами в области байтов Я думаю, SvPVbyte входит в игру, но как?

Моя проблема. Я уже успешно проанализировал массив Perl XYZ (в пределах хэша массивов) с примером индекса 6789) в Inline:C с Perl:

$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

Это работает отлично. Но допустим, у меня есть очень длинная строка байтов (около 10-50 МБ) в Perl $xyz="\x09\x07\x44\xaa......

Теперь я хочу передать ссылку на этот SV и пройти 9-байтовые шаги (например, substr) в части C через эту строку, не копируя ее полностью, например, в собственный массив C.

Проходная часть: первые 4 байта должны быть проверены по эталонному 4-байтовому значению ABC, которое также должно быть в вызове функции. При необходимости я могу предварительно распаковать эту поисковую фразу "N" и вызвать функцию с целым числом. Если позиция 0 не была успешной, прыжок / увеличение на 9 байтов продолжаются, если она успешна, я верну найденную позицию в качестве возврата.

Огромное спасибо.

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 ... */
    }
}

[Это ответ на вопрос в комментариях]

  • НИКОГДА не используйте 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));
Другие вопросы по тегам