2017-10-12 52 views
8

Użycie XS próbuję przekazać wartości z tablicy C do tablicy Perla, której można użyć w skrypcie.perl xs - zwracana tablica perl z tablicy c

Oto kod z mojego pliku xs:

AV * 
DoubleArray::getPerlArray() 
    CODE: 
    r = newAV(); 
    for(size_t i=0; i < THIS->count; i++) 
    { 
     av_push(RETVAL,newSVnv(THIS->data[i])); 
    } 
    OUTPUT: 
    RETVAL 

To kompiluje w porządku, ale gdy uruchomię następujących w Perlu:

my @d = $C->getPerlArray(); 
foreach(@d) 
{ 
    print "$_\n"; 
} 

To po prostu drukuje ARRAY(0x1408cdc) gdy ja spodziewałem się drukiem lista liczb.

Jak mogę zmodyfikować mój kod, aby poprawnie odesłać tablicę perl?

+0

https://www.nntp.perl.org/group/perl.xs/2011/06/msg2626.html wydaje się być odpowiedni – simbabque

+0

@simbabque Widziałem już ten przykład wcześniej. To trochę bałagan. Trudno się uczyć. –

+0

Czy mógłbyś podzielić się niektórymi rzeczami, których nauczyłeś się już ze społecznością? Możesz dodać rozdział lub dwa do https://github.com/xsawyerx/xs-fun. :-) – simbabque

Odpowiedz

9

Podsłówki Perl mogą zwracać (0 lub więcej) skalary. Gdy próbujesz zwrócić tablicę (niemożliwe bez awarii Perla!), Domyślna typemap zwróciła odwołanie do tej tablicy.

Zwróć uwagę, że twój program również wycieka z pamięci (ponieważ domyślna karta typów dla AV* powinna umniejszyć twoją tablicę, ale jej nie).


Wracając odniesienie metoda 1

AV* /* Returns: sv_2mortal(newRV(RETVAL)) */ 
DoubleArray::getPerlArrayRef() 
    PREINIT: 
     size_t i; 
    CODE: 
     RETVAL = (AV*)sv_2mortal((SV*)newAV()); 
     for (i=0; i < THIS->count; ++i) { 
      av_push(RETVAL, newSVnv(THIS->data[i])); 
     } 

    OUTPUT: 
     RETVAL 

kontroli szczelności pamięci:

  • Array RefCnt: ​​1 (newAV) -1 [opóźnione] (sv_2mortal) + 1 (newRV) = 1 [opóźniony] (własność b Y odniesienia)
  • RefCnt referencyjnego: 1 (newRV) -1 [opóźnione] (sv_2mortal) = 0 [opóźnione]

Perl

my $array = $C->getPerlArrayRef(); 
say for @$array; 

Wracając odniesienie, metoda 2

SV* /* Returns: sv_2mortal(RETVAL) */ 
DoubleArray::getPerlArrayRef() 
    PREINIT: 
     AV* av; 
     size_t i; 
    CODE: 
     av = newAV(); 
     RETVAL = newRV_noinc((SV*)av); 
     for (i=0; i < THIS->count; ++i) { 
      av_push(av, newSVnv(THIS->data[i])); 
     } 

    OUTPUT: 
     RETVAL 

kontroli szczelności pamięci:

  • RefCnt Array: 1 (newAV) +0 (newRV_noinc) = 1 (własność przez odniesienie)
  • referencyjnego RefCnt: ​​1 (newRV_noinc) -1 [opóźnione] (sv_2mortal) = 0 [opóźnione]

Perl < jak wyżej>


Zwracanie referencji, metoda 3

void 
DoubleArray::getPerlArrayRef() 
    PREINIT: 
     AV* av; 
     size_t i; 
    PPCODE: 
     av = newAV(); 
     mXPUSHs(newRV_noinc((SV*)av)); 
     for (i=0; i < THIS->count; ++i) { 
      av_push(av, newSVnv(THIS->data[i])); 
     } 

sprawdzić wyciek pamięci:

  • RefCnt Array: 1 (newAV) +0 (newRV_noinc) = 1 (własność przez odniesienie)
  • Podpunkt odniesienia: 1 (newRV_noinc) -1 [opóźniony] (mXPUSHs) = 0 [opóźniony]

Perl: < samo jak powyżej>


Powracający skalary

musimy sprawdzić kontekst, ponieważ nie możemy miejsce więcej niż jeden skalar na stosie poza kontekstem listy.

void 
DoubleArray::getElements() 
    PREINIT: 
     size_t i; 
     U8 gimme = GIMME_V; 
    PPCODE: 
     if (gimme == G_ARRAY) { 
      EXTEND(SP, THIS->count); 
      for (i=0; i < THIS->count; ++i) { 
       mPUSHn(THIS->data[i]); 
      } 
     } 
     else if (gimme == G_SCALAR) { 
      mXPUSHu(THIS->count); 
     } 

Perl:

my $count = $C->getElements(); 
say $count; 

my @array = $C->getElements(); 
say for @array; 

Uwaga: RefCnt ubytek przez sv_2mortal jest opóźnione aż rozmówca ma szansę zwiększa zawartość RefCnt.

+2

Doskonała odpowiedź! Dzięki! –

+0

Świetna odpowiedź! Uwaga dla wersji Perl> = 5.16, możesz również zadeklarować typem "AV * \t T_AVREF_REFCOUNT_FIXED", jeśli nie zależy Ci na kompatybilności wstecznej, zobacz sekcję * "Zwracanie SV, AV i HV przez RETVAL" * w ['perlxs'] (https://perldoc.perl.org/perlxs.html#Returning-SVs%2c-AVs-and-HVs-through-RETVAL), aby uzyskać więcej informacji. –

+0

Tak, doszedłem do wniosku, że odpowiedź była już wystarczająco długa bez jej przedstawienia. – ikegami