2014-04-07 12 views
7

Le mie domande riguardano il funzionamento del codice C in linea: è necessario utilizzare le funzioni di stack inline (Inline_Stack_Vars) per passare le variabili dentro e fuori, o è appropriato in questo contesto modificare semplicemente una variabile?Perl Inline :: C: Are Inline_Stack_Vars ecc. Necessari per evitare perdite di memoria (corrispondenza dei caratteri di biosequenza)

Per la visualizzazione di dati di biosequenza, devo mostrare solo le differenze tra due stringhe allineate; per esempio. Alla luce di questi due stringhe:..

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

voglio ottenere questo (i caratteri corrispondenti nella seconda stringa sostituito con' di

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

ho un sacco di sequenze (milioni di Illumina legge), così si sono rivolti a inline :: c per l'abbinamento dei caratteri il codice inline seguente sembra funzionare bene (modificando il secondo argomento della funzione add_matchchars sul posto):.

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

Ma 1) è i t ragionevolmente efficiente (c'è un modo più intelligente/migliore)? e 2) riuscirà a perdere memoria?

+0

'Inline_Stack_ *' è un mezzo per accedere agli elenchi di argomenti di lunghezza variabile.Non ha nulla a che fare con perdite di memoria. – ikegami

+0

Inline_Stack _.... sono macro che possono essere utilizzate al posto di macro di livello inferiore normalmente utilizzate durante il passaggio di parametri avanti e indietro sullo stack di chiamate usando Perl XS. Sono utili. Se si accede allo stack di chiamata dei parametri, in genere si utilizzano questi macro o macro di livello inferiore XS. – DavidO

risposta

6

Non si deve fare affidamento sullo char * di uno scalare modificabile, o addirittura sul buffer originale dello scalare. Invece, restituire una nuova stringa.

La macro Inline_Stack_Vars è utile solo quando si ha a che fare con un numero variabile di argomenti o più valori di ritorno. Né è il caso qui.

Il tuo codice non presenta attualmente perdite di memoria (non si alloca memoria all'interno della funzione C), ma alcuni problemi sono inclusi. . stile, possibili segfaults (corretta while(seq1char = *seq1++ , seq2char = *seq2++) al while((seq1char = *seq1++) && (seq2char = *seq2++)) e il fatto che le stringhe Perl possono contenere NULs all'interno della stringa

penso che è generalmente una migliore idea di avere la funzione C prendere direttamente scalari Approssimativamente:.

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

Grazie a @ikegami per le tue modifiche, ho imparato molto da loro :) – amon

+0

np. Se si volesse modificare '$ seq2' sul posto, usare' SvPVbyte_force' invece di 'SvPVbyte', quindi modificare' seq2' invece di modificare 'seq3'. – ikegami

+0

Grazie a @amon - questo tipo di feedback è esattamente ciò di cui avevo bisogno. – user3507704