Как я могу передать массив функции C в Perl XS?
Как передать массив Perl по ссылке на модуль C XS?
my @array = ( 1..20 );
XSTEST::test_array_passing(\@array);
Что мне делать в XS, чтобы он видел массив?
2 ответа
XS может получить ссылку на ARRAY как AV*
или SV*
, Последний должен быть разыменован в AV*
,
use Inline C => DATA;
@array = (1 .. 20);
$r = sum_of_elements1(\@array);
$s = sum_of_elements2(\@array);
print "$r $s\n"; # produces output: "210 210\n"
__END__
__C__
double sum_of_elements1(AV* array)
{
int i;
double sum = 0.0;
for (i=0; i<=av_len(array); i++) {
SV** elem = av_fetch(array, i, 0);
if (elem != NULL)
sum += SvNV(*elem);
}
return sum;
}
double sum_of_elements2(SV* array_ref)
{
AV* array;
if (!SvROK(array_ref) || SvTYPE(SvRV(array_ref)) != SVt_PVAV)
croak("expected ARRAY ref");
array = (AV*) SvRV(array_ref);
return sum_of_elements1(array);
}
Файл.xs, созданный этим кодом, объявляет:
double
sum_of_elements1 (array_ref)
SV * array_ref
double
sum_of_elements2 (array)
AV * array
Редактировать: в sum_of_element2()
, добавил проверку, что *SV была ссылкой на массив.
Вы не можете передать массив Perl и автоматически преобразовать его, скажем, в массив C. Для этого вам придется прибегнуть к XS и perlapi. Причина довольно проста: массив perl содержит нетипизированные скаляры. Массив A C содержит N элементов одного типа.
Что вы можете сделать, это иметь XSUB
это занимает SV*
, SV
обозначает скалярное значение. Это естественно включает в себя ссылки (RV
) и, следовательно, также ссылки на массивы (AV
"S).
Вот как вы можете проверить, является ли данный SV*
Источник - это ссылка на массив:
SV* tmpSV;
AV* theArray;
if (SvROK(source)) { /* it's a reference */
tmpSV = (SV*)SvRV(source); /* deref */
if (SvTYPE(tmpSV) == SVt_PVAV) { /* it's an array reference */
theArray = (AV*)tmpSV;
/* do stuff with the array here */
}
}