2014-04-07 8 views
7

Moje pytanie dotyczy działającego kodu C w linii: czy konieczne jest korzystanie z funkcji stosu inline (Inline_Stack_Vars) do przekazywania zmiennych do i na zewnątrz, czy może w tym kontekście wystarczy zmodyfikować zmienną w miejscu?Perl Inline :: C: Są Inline_Stack_Vars itp. Potrzebne, aby uniknąć wycieków pamięci (dopasowanie sekwencji elementów)

Do wyświetlania danych o sekwencji biologicznej, muszę pokazać tylko różnice między dwoma wyrównanymi ciągami; na przykład Biorąc pod uwagę te dwa ciągi:..

ATCAGAAA--GACATGGGCCAAAGATTAA-CAGTGGCCATTGACAGGA-- 
    --CCCCAACTGACAGGGGGCAAAGATTAA-CAGTGGCCATTG---GGA-- 

chcę dostać to (Dopasowanie znaków w drugim ciągiem zastąpione”'S

--.CCC..CT....G...G..........-............---...-- 

Mam wiele sekwencji (miliony Illumina czyta), więc zwrócili się do inline :: c do dopasowywania znaków Poniższy kod wplatany wydaje się działać dobrze (zmiana drugi argument do funkcji add_matchchars w miejscu).

#!/usr/bin/perl 
use Inline C; 

my($seq1,$seq2) = qw/ ATCAGAAA--GACATGGGCCAAAGATTAA-CAGTGGCCATTGACAGGA-- 
         --CCCCAACTGACAGGGGGCAAAGATTAA-CAGTGGCCATTG---GGA-- /; 

print $seq1,"\n"; 
print $seq2,"\n"; 
add_matchchars($seq1,$seq2); 
print $seq2,"\n"; 

__END__ 

__C__ 

void add_matchchars(char *seq1, char *seq2) { 
    int seq1char; 
    int seq2char; 
    while(seq1char = *seq1++ , seq2char = *seq2++) { 
     if (seq1char == seq2char) { 
      *seq2--; 
      if (seq1char != '-') { 
       *seq2 = '.'; 
      } 
      *seq2++; 
     } 
     //printf("%c-%c\n",seq1char,seq2char); 
    } 
// printf("%s\n%s\n",seq1,seq2); 
} 

Ale 1) to ja t racjonalnie wydajne (czy istnieje mądrzejszy/lepszy sposób)? i 2) czy spowoduje wyciek pamięci?

+0

'Inline_Stack_ *' jest sposobem dostępu do list argumentów o zmiennej długości.Nie ma nic wspólnego z wyciekami pamięci – ikegami

+0

Inline_Stack _.... są makrami, które mogą być użyte w miejsce makr nawet niższego poziomu normalnie używanych przy przekazywaniu parametrów tam iz powrotem na stosie wywołań przy użyciu Perla XS, są wygodniejsze. Jeśli korzystasz ze stosu wywołań parametrów, zazwyczaj używasz tych makr lub niższy poziom XS zestaw makr. – DavidO

Odpowiedz

6

Nie powinieneś polegać na char * skalaru, który można modyfikować, a nawet być oryginalnym buforem skalarnym. Zamiast tego zwróć nowy ciąg.

Makro Inline_Stack_Vars jest przydatne tylko w przypadku zmiennej liczby argumentów lub wielu wartości zwracanych. Tak też nie jest w tym przypadku.

Twój kod nie cierpi obecnie na przecieki pamięci (nie przypisujesz pamięci wewnątrz funkcji C), ale występują pewne problemy, w tym: . styl, ewentualne naruszenia ochrony pamięci (prawidłowe while(seq1char = *seq1++ , seq2char = *seq2++) do while((seq1char = *seq1++) && (seq2char = *seq2++)) oraz fakt, że ciągi Perl może zawierać nuls wewnątrz łańcucha

myślę, że jest generalnie lepszy pomysł, aby mieć swoją funkcję C wziąć bezpośrednio skalary grubsza.

SV *add_matchchars(SV *seq1_sv, SV *seq2_sv) { 
    STRLEN len1, len2; 
    char *seq1 = SvPVbyte(seq1_sv, len1); 
    char *seq2 = SvPVbyte(seq2_sv, len2); 
    STRLEN min_len = len1 < len2 ? len1 : len2; 
    SV *seq3_sv = newSVpvn(seq2, min_len); 
    char *seq3; 
    STRLEN i; 

    seq3 = SvPVX(seq3_sv); 
    for (i = 0; i < min_len; ++i) { 
     if (seq1[i] == seq2[i]) 
      seq3[i] = '.'; 
    } 

    return seq3_sv; 
} 
+1

Dzięki @ikegami za edycje, wiele się od nich nauczyłem :) – amon

+0

np. Jeśli chcesz zmodyfikować '$ seq2' na miejscu, użyj' SvPVbyte_force' zamiast 'SvPVbyte', a następnie zmodyfikuj' seq2' zamiast modyfikować 'seq3'. – ikegami

+0

Dzięki @amon - tego rodzaju opinie są dokładnie tym, czego potrzebowałem. – user3507704