2009-10-09 5 views
7

Stavo cercando di emettere un array di caratteri terminato non nullo in un file.C++ output di array di char terminato non nullo

La cosa reale è che sto ricevendo pacchetti e poi stampo i loro campi.

Ora come questi campi non sono terminati con null, ad esempio, un segmento di dati che ha una dimensione di 512 ma può o non può essere completamente occupato.

Quando scrivo questi dati su un file sto usando la semplice funzione sovraccaricata < < che non sa nulla dei dati reali e cerca solo la conclusione del segmento di dati.

Quindi, come posso dire alla funzione di output di scrivere solo questo numero specifico di byte?

Invece di usare qualcosa di simile, che è costoso di chiamare ogni volta:

enter code here 

bytescopied = strncpy(dest, src, maxbytes); 

if (bytescopied < 0) { // indicates no bytes copied, parameter error 

    throw(fit);   // error handler stuff here 

} else if (bytescopied == maxbytes) { 

    dest[maxbytes-1] = '\0'; // force null terminator 

} 

risposta

16

Se si vuole mettere esattamente maxbytes byte, utilizzare il metodo write

stream.write(buffer, maxbytes); 

Se si può avere meno byte nel buffer, come fai a sapere quanti di loro buffer contiene? Se '\0' marchi tampone fine, si può scrivere:

stream.write(buffer, std::find(buffer, buffer+maxbytes, '\0') - buffer); 
+0

Nella seconda chiamata, l'intero secondo parametro è solo un modo indiretto di chiamare il vecchio 'strlen'. Ma in tal caso, potresti anche usare il modo più idiomatico per l'intera istruzione: 'stream << buffer'. –

+0

N. strlen non si fermerà dopo max. –

+0

'strnlen' sarà. Una chiamata strnlen apparirà molto più pulita: 'strnlen (buffer, maxbytes)'. Non c'e 'niente da fare con i puntatori o qualcosa di simile. – gnud

3

Una soluzione economica sarebbe quella di avere un buffer che ha spazio per un carattere aggiuntivo nullo e appena messo un carattere null al puntare quando si conosce la dimensione effettiva e quindi inviare il buffer con terminazione null come si fa già. Veloce e affidabile.

+0

Sì, è possibile salvare quel carattere in più in una variabile temporanea. Una volta terminata la stampa, è sufficiente ripristinarla. –

3

Questo funziona, ma non è sicuro contro chiamando accidentalmente la versione standard di char*operator<<:

#include <iostream> 

template <unsigned N> 
std::ostream& operator<< (std::ostream& out, const char (& data) [N]) 
{ 
    out.write (data, N); 
    // or out.write (data, strnlen (data, N)); 
    // if you want to stop at a '\0' in the data 
    return out; 
} 


struct Foo { 
    char one[5]; 
    char two[1]; 
    char three[5]; 
}; 

int main (void) 
{ 
    using namespace std; 

    Foo foo = { 
     { 'h', 'e', 'l', 'l', 'o' }, 
     { ' ' }, 
     {'w', 'o', 'r', 'l', 'd'} }; 

    cout << foo.one; 
    cout << foo.two; 
    cout << foo.three; 
    cout << endl; 
} 

Questo è più sicuro, utilizzando un tipo maxw che limita la lunghezza del prossimo char* uscita:

struct maxw { 
    unsigned n; 
    maxw (unsigned n) : n (n) { } 
}; 

struct maxw_stream { 
    std::ostream& stream; 
    unsigned n; 
    maxw_stream (std::ostream& stream, unsigned n) : 
      stream (stream), 
      n (n) { 
    } 
}; 

maxw_stream operator<< (std::ostream& out, const maxw& m) 
{ 
    return maxw_stream (out, m.n); 
} 

std::ostream& operator<< (const maxw_stream& out, const char* data) 
{ 
    out.stream.write (data, strnlen (data, out.n)); 
    return out.stream; 
} 

// eg: 
cout << maxw(4) << "Hello World!" << endl; 
// Hell\n 
cout << maxw(100) << "Hello World!" << endl; 
// Hello World!\n 
+0

Il problema con strnlen è che AFAIK non è standard. E la tua funzione template è carina, ma se un buffer viene passato come un semplice puntatore, non un array, non ci sarà alcun avvertimento, verrà chiamata solo la funzione standard di output della stringa c. –

+0

È in C99 da dieci anni e IIRC C++ 0x porterà tutti gli standard C99. –

+0

Bene, ho cercato http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf e non ho trovato strnlen. –

0

vedo principalmente due soluti ons.

In caso di dati ASCII:

memset(dest,0,destlength); 
bytescopied = strncpy(dest, src, maxbytes); 

quindi avrete sempre chiaro stringa null-terminata in buffor.

Seconda in caso di dati ASCII:

std::string yourASCII(src,maxbytes); 
yourASCII.c_str() // would be null terminated. 
0

Se non si preoccupano l'ultimo byte, si può solo

buffer[buffersize-1] = 0; 

e poi nutrire tampone a qualsiasi funzione di stringa che si desidera. Se è più breve, tutto verrà eseguito sul terminatore nullo già esistente e, se non ci fosse un terminatore, verrà eseguito su quello appena creato.

Ed è veloce :)

Problemi correlati