【发布时间】:2009-10-01 12:48:50
【问题描述】:
如何通过引用 C XS 模块来传递 Perl 数组?
my @array = ( 1..20 );
XSTEST::test_array_passing(\@array);
在 XS 中我该怎么做才能看到数组?
【问题讨论】:
如何通过引用 C XS 模块来传递 Perl 数组?
my @array = ( 1..20 );
XSTEST::test_array_passing(\@array);
在 XS 中我该怎么做才能看到数组?
【问题讨论】:
XS 可以以AV* 或SV* 的形式接收对ARRAY 的引用。后者必须取消引用到 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 是对数组的引用的检查。
【讨论】:
use strict; 和use warnings; 是怎么回事?
tmpSV 必须是拼写错误(因为这是一个未定义的 var),从 2017 年起,该行应写为:if (! SvROK(array_ref) || SvTYPE(SvRV(array_ref)) != SVt_PVAV){。我不打算去编辑你的答案。这个答案肯定帮助我解决了我遇到的一个合理相关的问题,所以我想我会评论我的发现。
您不能传递一个 Perl 数组并让它自动转换为,例如,一个 C 整数数组。您将不得不求助于 XS 和 perlapi 来执行此操作。原因很简单:perl 数组包含无类型的标量。一个 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 */
}
}
【讨论】: