Perl内联C:将Arrayref传递给C函数

时间:2013-08-17 18:04:03

标签: perl arrayref inline-c

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

首先,为了证明我可以让Inline 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.

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

3 个答案:

答案 0 :(得分:12)

Inline :: C非常聪明,可以根据您的C函数的类型签名从SV中提取值。但是如果你想将复杂的Perl结构传递给C函数,你需要使用Perl API来提取值。所以,这是你需要知道的问题:

数组是名为struct的C AV的实例。引用由名为struct的{​​{1}}实现。所有这些都是名为RV的基础struct的“子类型”(有点)。

为了使这个功能起作用,我们需要做一些事情。

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

    SV

    有点让你欣赏Perl做了多少工作。 :)

    现在,您不必像该示例那样超级明确。你可以通过内联做事来摆脱一些临时变量,例如

    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 );
    }
    

    将无需声明printf( "C = %f\n", SvNV( *value ) ); 。但是我想清楚地说明在C中遍历Perl结构需要多少解除引用和类型检查。

    正如@mob在下面指出的那样,你实际上并不需要做所有工作(尽管熟悉它的工作方式是个好主意。)

    Inline :: C非常智能,如果你将你的函数声明为

    num

    它将自动为您打开void foo( AV *abc ) { ... } ,您可以直接进入AV步骤。

    如果所有这一切看起来令人困惑,我强烈建议你看一下:

    1. Perlguts Illustrated PDF,然后
    2. perlguts联机帮助页,然后
    3. Inline::C Cookbook,咨询
    4. perlapi联机帮助页。

答案 1 :(得分:4)

错误的数据类型。

use Inline 'C';

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

__END__
__C__
void foo(SV* abc) {
    sv_dump(abc);
}

答案 2 :(得分:4)

Inline::C代码中:

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

  array = (AV *)SvRV( reference );

  ...
}

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