12

我无法使用 Inline C 将 arrayrefs 传递给 C 函数。我需要一些帮助。

首先,为了证明我可以让内联 C 工作,我将一个标量值传递给 C 函数:

#!/usr/bin/perl -I. 
#
# try1.pl
#
use Inline C;

my $c = 3.8;
foo( $c );

__END__
__C__
void foo( double c )
{
   printf( "C = %f\n", c );
}

并运行它:

% ./try1.pl
C = 3.800000

现在做同样的事情,但使用 arrayref:

#!/usr/bin/perl -I. 
# 
# try2.pl
#
use Inline C;

my @abc = (1.9, 2.3, 3.8);
foo( \@abc );

__END__
__C__
void foo( double *abc )
{
    printf( "C = %f\n", abc[2] );
}

运行:

% ./try2.pl
Undefined subroutine &main::foo called at ./try1.pl line 7.

任何想法我做错了什么?非常感谢帮助!

4

3 回答 3

13

Inline::C 足够聪明,可以SV根据 C 函数的类型签名从 's 中提取值。但是,如果您想将复杂的 Perl 结构传递给 C 函数,则需要使用Perl API来提取值。因此,对于此问题,您需要了解以下内容:

数组是 C 的一个实例,struct称为AV. 引用由被struct调用的 an实现RV。所有这些都是struct名为SV.

所以为了使这个函数工作,我们需要做一些事情。

  1. 将参数类型更改为SV *(指向 的指针SV)。
  2. 使用 API 检查此特定SV值是否是引用而不是其他类型的标量
  3. 检查 RV 以确保它指向一个数组而不是其他东西。
  4. 取消引用RV以获得SV它指向的那个。
  5. 因为我们知道这SV是一个数组,所以将其转换为AV并开始使用它。
  6. 查找该数组的第三个元素,即另一个SV.
  7. 检查SV我们从数组中得到的 是一个适合 C 的数值printf
  8. 从中提取实际数值SV
  9. 打印消息

因此,将所有这些放在一起,我们会得到这样的结果:

use Inline C;

my @abc = (1.9, 2.3, 3.8);
foo( \@abc );

__END__
__C__
void foo( SV *abc )
{
    AV *array;     /* this will hold our actual array */
    SV **value;    /* this will hold the value we extract, note that it is a double pointer */
    double num;    /* the actual underlying number in the SV */

    if ( !SvROK( abc ) ) croak( "param is not a reference" );
    if ( SvTYPE( SvRV( abc ) ) != SVt_PVAV ) croak( "param is not an array reference" );

    /* if we got this far, then we have an array ref */
    /* now dereference it to get the AV */
    array = (AV *)SvRV( abc );

    /* look up the 3rd element, which is yet another SV */
    value = av_fetch( array, 2, 0 );

    if ( value == NULL ) croak( "Failed array lookup" );
    if ( !SvNOK( *value ) ) croak( "Array element is not a number" );

    /* extract the actual number from the SV */
    num = SvNV( *value );

    printf( "C = %f\n", num );
}

Kinda 让您欣赏 Perl 在幕后所做的工作。:)

现在,您不必像该示例那样非常明确。您可以通过内联处理来摆脱一些临时变量,例如

printf( "C = %f\n", SvNV( *value ) );

将消除申报的需要num。但我想弄清楚在 C 中遍历 Perl 结构需要多少解引用和类型检查。

正如@mob 在下面指出的那样,您实际上不必做所有这些工作(尽管熟悉它的工作原理是个好主意。)

Inline::C 足够聪明,如果您将函数声明为

void foo( AV *abc ) { 
   ...
}

它会自动AV为您打开包装,您可以直接进入av_fetch步骤。

如果所有这些对您来说都令人困惑,我强烈建议您看一下:

  1. Perlguts插图PDF,然后
  2. perlguts手册页,然后
  3. The Inline::C Cookbook,同时咨询
  4. perlapi手册页。
于 2013-08-17T21:44:18.607 回答
4

在您的Inline::C代码中:

void foo( SV *reference ) {
  AV *array;

  array = (AV *)SvRV( reference );

  ...
}

然后将数组值作为AV类型处理。请参阅Perl Inline::C Cookbook

于 2013-08-17T18:35:09.597 回答
4

错误的数据类型。

use Inline 'C';

my @abc = (1.9, 2.3, 3.8);
foo( \@abc );

__END__
__C__
void foo(SV* abc) {
    sv_dump(abc);
}
于 2013-08-17T18:16:47.200 回答