2013-03-11 12 views
6

私はInline :: Cを使ってC関数を記述しようとしています。これはPerlへの配列参照を作成して返します。以下はスクリプトと出力です。配列を割り当てて適切に配置していますか?特に、SV*の仮配列を作成してav_makeに渡し、newRV_noincで作成した参照を返します。参照カウントは、Devel :: Peek :: Dumpで返された配列refを見るとうまくいくように見えますが、これはperlで直接作成された同じデータ構造と同じに見えます。Inline :: Cで配列リファレンスを作成して返しますか?

私はまだ死亡率/ sv_2mortalが何であるか、または私がここでそれを必要としているか理解していません。明らかに、Inline :: Cは、SV*を返す関数で自動的にsv_2mortalを呼び出します。これは関連性があるかもしれません。

#!/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 

答えて

7

あなたはperldoc perlgutsを読んでいますか?それはそこにあなたのほとんどの方法を取得する必要があります。 Inline::CAV*の戻り値も処理できます。あまりにも役立つかもしれない、私が書かれている

#!/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; 

Here is some code:私のような何かをするかもしれません。

+0

私は知りませんでした 'MUTABLE_SV'は、なぜそれが好まれていますか? typecastingを提案しないように[this(http://perldoc.perl.org/perlguts.html#Reference-Counts-and-Mortality)を更新する必要がありますか? –

+0

'const'をキャストしないようにします。私はパッチを提出します。 – ikegami

+0

あなたはperlapiにもパッチを当てたいと思うかもしれません。そこにも文書化されていなくても、それを使うのは嫌です。実際、私はそれがperldeltasで文書化されているだけです。これは、後のデルタで「削除された」メモがないことを恐れてAPIリファレンスとして使用しません。 –

5

私は死亡/ sv_2の死体が何であるか、または私がここに必要なのかまだ分かりません。どうやらInline :: CはSV *を返す関数で自動的にsv_2mortalを呼び出します。これは関連性があるかもしれません。

RVを割り当てたときに、そのRVが所有者になりました。あなたがそれを握ったら、あなたはその参照回数を減らす必要があります。しかし、他の誰もそれに言及していないので、それは現場で自由になるでしょう。減価償却は、減額された還付額の控除です。これは、呼び出し側に最初にそれをつかむ(そしてその参照回数を増やす)チャンスを与えます。

そうですが、RVは致命的である必要があります。はい、タイプマップは返されたSV *をあなたに犠牲にします。

あなたのコードにはバグはありませんが、Joel Berger氏が示したように、C配列を事前にビルドする必要はありません。彼のコードも大丈夫です。

戻り値の型がAV*の場合、型マップは配列への参照を作成しますが、配列自身を犠牲にすることはありません。あなたの2次戻りオプションは、このように

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

// Return type = AV* 
return MUTABLE_AV(sv_2mortal(MUTABLE_SV(newRV_noinc(arr))); 
+0

そしてなぜ私が何をしていたかについて私が思うよりも自分の考えを表現することに感謝します。これは私が自分自身をまっすぐに保つことができるものの一つです。乾杯! –

+0

@Joel Berger、私の主な目標は、彼がそれについて尋ねたので、死亡率を説明することでした。ノードとの重複が誤って発生しました。 – ikegami

関連する問題