SV
Inline::C は、C 関数の型シグネチャに基づいてから値を抽出するのに十分スマートです。しかし、複雑な Perl 構造を C 関数に渡したい場合は、Perl APIを使用して値を抽出する必要があります。したがって、この問題について知っておくべきことは次のとおりです。
配列は、struct
と呼ばれるC のインスタンスですAV
。struct
参照は、と呼ばれるによって実装されRV
ます。これらはすべて、struct
と呼ばれるベースの「サブタイプ」(一種) ですSV
。
したがって、この関数を機能させるには、いくつかのことを行う必要があります。
- パラメーターの型を
SV *
(へのポインターSV
) に変更します。
- API を使用して、これ
SV
が他の種類のスカラーではなく参照であるかどうかを確認します
- RV をチェックして、他のものではなく配列を指していることを確認します。
- を逆参照して、それが指している
RV
を取得します。SV
SV
これが配列であることはわかっているので、キャストしてAV
操作を開始します。
- その配列の 3 番目の要素を検索します。これは別の
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 );
}
ちょっと、Perl が内部でどれだけの作業を行っているかを理解できます。:)
さて、その例のように極端に明示的である必要はありません。インラインで実行することで、一時変数の一部を取り除くことができます。
printf( "C = %f\n", SvNV( *value ) );
を宣言する必要がなくなりnum
ます。しかし、C で Perl 構造をトラバースするには、どれだけの逆参照と型チェックが必要かを明確にしたかったのです。
また、@mob が以下で指摘しているように、実際にすべての作業を行う必要はありません (ただし、その仕組みをよく理解しておくことをお勧めします)。
Inline::C は十分スマートなので、関数を次のように宣言すると
void foo( AV *abc ) {
...
}
自動的に開梱され、すぐにステップAV
に進むことができます。av_fetch
これらすべてに困惑していると思われる場合は、以下をご覧になることを強くお勧めします。
- Perlguts Illustrated PDF、その後
perlguts
マンページ、そして
- Inline::C Cookbook、相談しながら
perlapi
マンページ。