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));