【问题标题】:How can I pass an array to a C function in Perl XS?如何将数组传递给 Perl XS 中的 C 函数?
【发布时间】:2009-10-01 12:48:50
【问题描述】:

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

my @array = ( 1..20 );

XSTEST::test_array_passing(\@array);

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

【问题讨论】:

    标签: perl xs


    【解决方案1】:

    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 是对数组的引用的检查。

    【讨论】:

    • 感谢您的回答,我会试试这个,但在这种情况下,我只能在 XS 文件中提供操作,我不能将我的数组操作放在单独的 C 文件中,因为我需要 AV/ SV 数据结构访问那里
    • Avinash:您可以将使用 perlapi 的代码放入任意 c 文件中。只需包含必要的 perl 标头即可。
    • 您还想检查引用是否是对数组的引用。
    • 哇,mobrule,代码中缺少use strict;use warnings; 是怎么回事?
    • tmpSV 必须是拼写错误(因为这是一个未定义的 var),从 2017 年起,该行应写为:if (! SvROK(array_ref) || SvTYPE(SvRV(array_ref)) != SVt_PVAV){。我不打算去编辑你的答案。这个答案肯定帮助我解决了我遇到的一个合理相关的问题,所以我想我会评论我的发现。
    【解决方案2】:

    您不能传递一个 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 */
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-09-28
      • 2011-11-06
      • 2016-12-21
      • 2013-10-06
      • 1970-01-01
      • 2022-01-11
      • 1970-01-01
      • 2011-03-14
      • 2018-11-14
      相关资源
      最近更新 更多