6

Perl への配列参照を作成して返す Inline::C を介して C 関数を作成しようとしています...以下は私のスクリプトと出力です。配列を適切に割り当てて配置していますか? 具体的には、 の一時的な配列を作成して にSV*渡しav_make、 で作成された参照を返しnewRV_noincます。返された配列 ref を Devel::Peek::Dump で見ると、参照カウントは問題ないように見えます。これは、perl で直接作成された同じデータ構造と同じように見えます。

sv_2mortal私は死の/が何であるか、またはここでそれが必要かどうかをまだ理解していません. どうやら、Inline::C はsv_2mortalを返す関数を自動的に呼び出しますがSV*、これは関連する場合と関連しない場合があります。

#!/usr/bin/env perl
use strict;
use warnings FATAL => "all";
use 5.010_000;
use Data::Dumper;
use autodie;

use Inline ('C');
use Devel::Peek;

my $from_perl = [0 .. 9];
my $from_c = inline_array_maker(10); #same as above but in C

say Dumper $from_perl;
Dump($from_perl);

say Dumper $from_c;
Dump($from_c);


__END__
__C__
SV* (int len){
    int i;
    SV ** tmp_buffer;
    AV * arr;

    tmp_buffer  = malloc(sizeof(SV*) * len);

    printf("allocating tmp_buffer of size %d\n", len);
    for (i = 0; i < len; i++) {
        tmp_buffer[i] = newSViv(i);
    }

    // is av_make the most efficient way of doing this?  
    printf("av_make\n");
    arr = av_make(len, tmp_buffer);

    printf("freeing tmp_buffer\n");
    for (i = 0; i < len; i++) {
        sv_free(tmp_buffer[i]);
    }
    free(tmp_buffer);

    return newRV_noinc(arr);
}

次の出力が得られます。

allocating tmp_buffer of size 10
av_make
freeing tmp_buffer
$VAR1 = [
        0,
        1,
        2,
        3,
        4,
        5,
        6,
        7,
        8,
        9
        ];

SV = IV(0x20c7520) at 0x20c7530
REFCNT = 1
FLAGS = (PADMY,ROK)
RV = 0x21c0fa8
SV = PVAV(0x25c7ec8) at 0x21c0fa8
    REFCNT = 1
    FLAGS = ()
    ARRAY = 0x25a0e80
    FILL = 9
    MAX = 9
    ARYLEN = 0x0
    FLAGS = (REAL)
    Elt No. 0
    SV = IV(0x20b2dd8) at 0x20b2de8
    REFCNT = 1
    FLAGS = (IOK,pIOK)
    IV = 0
    Elt No. 1
    SV = IV(0x20b2fb8) at 0x20b2fc8
    REFCNT = 1
    FLAGS = (IOK,pIOK)
    IV = 1
    Elt No. 2
    SV = IV(0x20c69f8) at 0x20c6a08
    REFCNT = 1
    FLAGS = (IOK,pIOK)
    IV = 2
    Elt No. 3
    SV = IV(0x20c6a10) at 0x20c6a20
    REFCNT = 1
    FLAGS = (IOK,pIOK)
    IV = 3
$VAR1 = [
        0,
        1,
        2,
        3,
        4,
        5,
        6,
        7,
        8,
        9
        ];

SV = IV(0x20d25c8) at 0x20d25d8
REFCNT = 1
FLAGS = (PADMY,ROK)
RV = 0x25ac6b8
SV = PVAV(0x25c7ea0) at 0x25ac6b8
    REFCNT = 1
    FLAGS = ()
    ARRAY = 0x25b9140
    FILL = 9
    MAX = 9
    ARYLEN = 0x0
    FLAGS = (REAL)
    Elt No. 0
    SV = IV(0x25aca80) at 0x25aca90
    REFCNT = 1
    FLAGS = (IOK,pIOK)
    IV = 0
    Elt No. 1
    SV = IV(0x25ac750) at 0x25ac760
    REFCNT = 1
    FLAGS = (IOK,pIOK)
    IV = 1
    Elt No. 2
    SV = IV(0x25ac5e8) at 0x25ac5f8
    REFCNT = 1
    FLAGS = (IOK,pIOK)
    IV = 2
    Elt No. 3
    SV = IV(0x25ac930) at 0x25ac940
    REFCNT = 1
    FLAGS = (IOK,pIOK)
    IV = 3
4

2 に答える 2

7

perldoc perlgutsを読んだことがありますか?それはあなたをそこへの道のほとんどに連れて行くはずです。戻り値もInline::C処理できます。AV*私は次のようなことをするかもしれません:

#!/usr/bin/env perl

use strict;
use warnings;

use Inline C => <<'END';
  AV* make_arrayref (int size) {
    int i;
    AV* ret = newAV();
    sv_2mortal((SV*)ret);
    for(i=0; i<size; i++) {
      av_push(ret, newSViv(i) );
    }
    return ret;
  }
END

my $arrayref = make_arrayref(10);
print "$_\n" for @$arrayref;

これが私が書いたいくつかのコードで、これも役立つかもしれません。

于 2013-03-11T22:02:45.727 に答える
5

Mortalization/sv_2mortal が何であるか、またはここで必要かどうかはまだわかりません。どうやら、Inline::C は SV* を返す関数で sv_2mortal を自動的に呼び出しますが、これは関連する場合と関連しない場合があります。

RV を割り当てた時点で、その所有者になります。保持を放棄する場合は、refcount をデクリメントする必要があります。しかし、他の誰も参照を保持していないため、その場で解放されます。Mortalizing は、refcount のデクリメントの遅延です。最初にそれを取得する (そしてその参照カウントをインクリメントする) 機会を呼び出し元に与えます。

そうです、RV は死体化する必要があり、そうです、typemap は返された SV* を死体化します。

あなたのコードにはバグがありませんが、Joel Berger が示したように、C 配列を事前に構築する必要はありません。彼のコードも問題ありません。

彼はまた、戻り値の型がAV*の場合、typemap は配列への (mortal) 参照を作成しますが、配列自体は mortalize しないことも示しました。したがって、2つの主要な返品オプションは

// Return type = SV*
return newRV_noinc(arr);

// Return type = AV*
return MUTABLE_AV(sv_2mortal(MUTABLE_SV(newRV_noinc(arr)));
于 2013-03-11T22:33:09.093 に答える