2013-03-11 9 views
6

Próbuję napisać funkcję C przez Inline :: C, która będzie tworzyć i zwracać odwołanie do Perla ... poniżej jest mój skrypt i wynik. Czy przydzielam tablicę i zapełniam ją poprawnie? W szczególności tworzę tymczasową tablicę z SV* i przekazuję je do av_make i zwracam referencję utworzoną za pomocą newRV_noinc. Liczenia odwołań wydają się w porządku, gdy patrzę na zwróconą tablicę ref z Devel :: Peek :: Dump, która wygląda identycznie z tą samą strukturą danych tworzoną bezpośrednio w perlu.Jak utworzyć i zwrócić arrayref w Inline :: C?

Nie rozumiem jeszcze, czym jest mortalization/sv_2mortal, lub jeśli potrzebuję tego tutaj. Najwyraźniej Inline :: C automatycznie wywołuje sv_2mortal na funkcjach zwracających SV*, które mogą lub nie mogą być istotne.

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

Otrzymuję następujące wyniki.

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 

Odpowiedz

7

Czy czytasz perldoc perlguts? Powinien dostać tam większość drogi. Inline::C może obsłużyć również wartość zwracaną AV*. Mogę zrobić coś takiego:

#!/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 mam napisane, które mogą pomóc też.

+0

Nie wiedziałem o 'MUTABLE_SV', dlaczego jest korzystne? Czy należy zaktualizować [this] (http://perldoc.perl.org/perlguts.html#Reference-Counts-and-Mortality), aby nie sugerować typowania? –

+0

Zapewnia, że ​​nie odrzucisz 'const'. Prześlę łatkę. – ikegami

+0

Być może zechcesz też załatać perlapi, nawet tam go nie udokumentować, a bez tego nie chciałbym go użyć. W rzeczywistości widzę tylko to udokumentowane w perldeltas, którego nie użyłbym jako odnośnika API, z obawy przed brakiem "usuniętej" notatki w późniejszej delcie. –

5

Nie rozumiem jeszcze, czym jest mortalization/sv_2mortal lub czy potrzebuję go tutaj. Najwyraźniej Inline :: C automatycznie wywołuje sv_2mortal na funkcjach zwracających SV *, które mogą lub nie mogą być istotne.

Po przydzieleniu RV, stałeś się jego właścicielem. Jeśli zrezygnujesz z posiadania go, musisz zmniejszyć jego licznik. Ale to uwolniłoby go na miejscu, ponieważ nikt inny nie ma na nie odniesienia. Mortalising to opóźniony dekrement rozliczeniowy. Daje rozmówcy szansę na pobranie go (i zwiększenie wartości ref.).

Tak, tak, RV musi zostać splądrowany, i tak, typografia spowoduje śmierć dla ciebie zwróconego SV *.

Twój kod jest wolny od błędów, ale jak pokazał Joel Berger, nie musisz już budować tablicy C. Jego kod jest również w porządku.

Pokazał także, że jeśli typem zwrotu jest AV*, to wówczas typemap utworzy odniesienie (śmiertelne) do tablicy, ale nie spowolni samej tablicy. Twoje dwie opcje powrotu po stronie pierwotnej są zatem

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

i

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

Dziękuję za sformułowanie moich myśli lepiej niż mogłem, dlaczego robię co.Jest to jedna z tych rzeczy, z których ledwo mogę się wyprostować, nie mówiąc o wyjaśnieniach. Twoje zdrowie! –

+0

@ Joel Berger, Moim głównym celem było wyjaśnienie śmiertelności, odkąd o to poprosił. Nakładanie się na twój węzeł nastąpiło nieumyślnie. – ikegami