12

Inline C を使用して C 関数に arrayrefs を渡すことができません。助けてください。

まず、インライン 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

SVInline::C は、C 関数の型シグネチャに基づいてから値を抽出するのに十分スマートです。しかし、複雑な Perl 構造を C 関数に渡したい場合は、Perl APIを使用して値を抽出する必要があります。したがって、この問題について知っておくべきことは次のとおりです。

配列は、structと呼ばれるC のインスタンスですAVstruct参照は、と呼ばれるによって実装されRVます。これらはすべて、structと呼ばれるベースの「サブタイプ」(一種) ですSV

したがって、この関数を機能させるには、いくつかのことを行う必要があります。

  1. パラメーターの型をSV *(へのポインターSV) に変更します。
  2. API を使用して、これSVが他の種類のスカラーではなく参照であるかどうかを確認します
  3. RV をチェックして、他のものではなく配列を指していることを確認します。
  4. を逆参照して、それが指しているRVを取得します。SV
  5. SVこれが配列であることはわかっているので、キャストしてAV操作を開始します。
  6. その配列の 3 番目の要素を検索します。これは別の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 );
}

ちょっと、Perl が内部でどれだけの作業を行っているかを理解できます。:)

さて、その例のように極端に明示的である必要はありません。インラインで実行することで、一時変数の一部を取り除くことができます。

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

を宣言する必要がなくなりnumます。しかし、C で Perl 構造をトラバースするには、どれだけの逆参照と型チェックが必要かを明確にしたかったのです。

また、@mob が以下で指摘しているように、実際にすべての作業を行う必要はありません (ただし、その仕組みをよく理解しておくことをお勧めします)。

Inline::C は十分スマートなので、関数を次のように宣言すると

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

自動的に開梱され、すぐにステップAVに進むことができます。av_fetch

これらすべてに困惑していると思われる場合は、以下をご覧になることを強くお勧めします。

  1. Perlguts Illustrated PDF、その後
  2. perlgutsマンページ、そして
  3. 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 クックブックを参照してください。

于 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 に答える