如何在Perl XS中将数组传递给C函数?

10

我该如何将Perl数组通过引用传递给C XS模块?

my @array = ( 1..20 );

XSTEST::test_array_passing(\@array);

在XS中,我应该怎么做才能看到这个数组?

2个回答

11

XS 可以接收一个数组的引用作为 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是否是数组引用的代码。


谢谢您的回答,我会尝试这个方法。但在这种情况下,我只能在XS文件中提供操作,无法将我的数组操作放在单独的C文件中,因为我需要在那里访问AV/SV数据结构。 - Avinash
1
Avinash:您可以将使用perlapi的代码放置在任意的c文件中,只需包含必要的perl头文件即可。 - tsee
你还想检查引用是否是数组的引用。 - tsee
1
哇,mobrule,这段代码为什么没有使用use strict;use warnings;呢? - Chris Lutz
1
tmpSV 必须是一个打字错误(因为它是未定义的变量),截至2017年,该行应该写成:if (! SvROK(array_ref) || SvTYPE(SvRV(array_ref)) != SVt_PVAV){。虽然我不打算编辑你的答案。但这个答案确实帮助了我解决了一个相关的问题,所以我想评论一下我发现的内容。 - stevieb
显示剩余2条评论

8
您无法传递Perl数组并自动将其转换为例如C整数数组。您需要使用XS和perlapi来完成此操作。原因非常简单:Perl数组包含未经类型化的标量。 C数组保存N个相同类型的项目。
您可以做的是编写一个接受SV*XSUBSV代表标量值。这自然包括引用(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 */
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接