10

如何通过引用 C XS 模块来传递 Perl 数组?

my @array = ( 1..20 );

XSTEST::test_array_passing(\@array);

我在 XS 中该怎么做才能看到数组?

4

2 回答 2

11

XS 可以以 anAV*或 an 的形式接收对 ARRAY 的引用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 是对数组的引用的检查。

于 2009-10-01T17:36:40.087 回答
8

你不能传递一个 Perl 数组并让它自动转换为,比如说,一个 C 整数数组。您将不得不求助于 XS 和perlapi来做到这一点。原因很简单:perl 数组包含无类型的标量。AC 数组包含 N 个相同类型的项目。

你可以做的是有一个XSUB需要一个SV*. SV代表标量值。这自然包括引用 ( RV),因此也包括对数组 ( AV) 的引用。

以下是检查给定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 */
  }
}
于 2009-10-01T17:46:28.937 回答