How can I pass Perl array by reference to C XS module?
my @array = ( 1..20 );
XSTEST::test_array_passing(\@array);
What do I do in XS so it sees the array?
How can I pass Perl array by reference to C XS module?
my @array = ( 1..20 );
XSTEST::test_array_passing(\@array);
What do I do in XS so it sees the array?
XS can receive a ref to ARRAY as either an AV*
or an SV*
. The latter would have to be dereferenced to an 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);
}
The .xs file produced by this code declares:
double
sum_of_elements1 (array_ref)
SV * array_ref
double
sum_of_elements2 (array)
AV * array
Edit: in sum_of_element2()
, added the check that the *SV was a reference to an array.
use strict;
and use warnings;
in that code? –
Kent strict
and warnings
would make it. –
Divertissement tmpSV
must be a typo (as that's an undefined var), and as of 2017, that line should be written as: if (! SvROK(array_ref) || SvTYPE(SvRV(array_ref)) != SVt_PVAV){
. I wasn't about to go editing your answer though. This answer definitely helped me with a reasonably related issue I was having, so I thought I'd comment on what I found. –
Caecilian You can't pass a Perl array and have it automagically converted to, say, a C array of ints. You will have to resort to XS and the perlapi to do this. The reason is quite simple: a perl array contains untyped scalars. A C array holds N items of the same type.
What you can do is have an XSUB
that takes an SV*
. SV
stands for scalar value. This naturally includes references (RV
) and thus also references to arrays (AV
's).
Here's how you can check whether a given SV*
source is a reference to an array:
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 */
}
}
© 2022 - 2024 — McMap. All rights reserved.