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

And*_*oni 12 perl inline-c arrayref

我无法使用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 );
}
Run Code Online (Sandbox Code Playgroud)

并运行它:

% ./try1.pl
C = 3.800000
Run Code Online (Sandbox Code Playgroud)

现在做同样的事情,但使用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] );
}
Run Code Online (Sandbox Code Playgroud)

运行:

% ./try2.pl
Undefined subroutine &main::foo called at ./try1.pl line 7.
Run Code Online (Sandbox Code Playgroud)

我有什么想法我做错了吗?非常感谢!

fri*_*edo 13

Inline :: C足够智能,可以SV根据你的C函数的类型签名从中提取值.但是如果你想将复杂的Perl结构传递给C函数,你需要使用Perl API来提取值.那么,这是你需要知道的这个问题:

数组是被struct调用的C的实例AV.引用由被struct调用者实现RV.所有这些都是被struct称为基础的"亚型"(有点)SV.

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

  1. 将参数类型更改为SV *(指向an的指针SV).
  2. 使用API​​检查此特定SV是否是引用,而不是某种其他类型的标量
  3. 检查RV以确保它指向一个数组,而不是其他东西.
  4. 取消引用RV以获得SV它指向的内容.
  5. 因为我们知道这SV是一个数组,所以将它转换为AV并开始使用它.
  6. 查找该数组的第三个元素,这是另一个元素SV.
  7. 检查SV我们从数组得到的数值是否适合Cprintf
  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 );
}
Run Code Online (Sandbox Code Playgroud)

Kinda让你欣赏Perl在引擎盖下做了多少工作.:)

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

printf( "C = %f\n", SvNV( *value ) );
Run Code Online (Sandbox Code Playgroud)

将消除宣布的必要性num.但是我想说清楚在C中遍历Perl结构需要多少解除引用和类型检查.

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

如果你声明你的函数,Inline :: C足够聪明

void foo( AV *abc ) { 
   ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

  1. 然后是Perlguts Illustrated PDF
  2. perlguts联机帮助页,然后
  3. 内联中:C菜谱,而咨询
  4. perlapi手册页.

  • 可以声明函数`void foo(AV*array){...`并让Perl/Inline :: C处理前三个步骤. (2认同)

dax*_*xim 3

数据类型错误。

use Inline 'C';

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

__END__
__C__
void foo(SV* abc) {
    sv_dump(abc);
}
Run Code Online (Sandbox Code Playgroud)