我无法使用内联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.

有什么想法我做错了吗?帮助极大的赞赏!

最佳答案

Inline::C足够聪明,可以根据C函数的类型签名从SV提取值。但是,如果要将复杂的Perl结构传递给C函数,则需要使用Perl API提取值。因此,这是您需要解决的问题:

数组是称为struct的C AV的实例。引用由称为structRV实现。所有这些都是称为struct的基本SV的“子类型”(种类)。

因此,要使此功能正常工作,我们需要做一些事情。

  • 将参数类型更改为SV *(指向SV的指针)。
  • 使用API​​来检查此特定SV是否是引用,而不是其他某种标量
  • 检查RV以确保它指向的是数组而不是其他数组。
  • 取消引用RV以获取其指向的SV
  • 既然我们知道SV是一个数组,请将其转换为AV并开始使用它。
  • 查找该数组的第三个元素,这是另一个SV
  • 检查我们从数组中获得的SV是适合于C的数值printf
  • SV中提取实际数值。
  • 打印消息

  • 因此,将所有这些放在一起,我们得到的是这样的:
    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在下面指出的那样,您实际上不必做所有的工作(尽管熟悉它的工作方式是个好主意。)

    内联:: C非常聪明,如果您将函数声明为
    void foo( AV *abc ) {
       ...
    }
    

    它将自动为您解开AV,您可以直接进入av_fetch步骤。

    如果这一切似乎让您感到困惑,我强烈建议您看一下:
  • Perlguts Illustrated PDF,然后是
  • perlguts 联机帮助页,然后
  • 咨询
  • 时的Inline::C Cookbook
  • perlapi 联机帮助页。
  • 关于Perl内联C : Passing Arrayref to C Function,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18291827/

    10-12 06:30