2009-10-09 9 views
7

Estaba tratando de generar una matriz de caracteres terminada no nula en un archivo.C++ matriz terminada no nula que da como resultado

Lo cierto es que recibo paquetes y luego imprimo sus campos.

Ahora, como estos campos no tienen terminación nula, por ejemplo, un segmento de datos que tiene un tamaño de 512 pero que puede o no estar completamente ocupado.

Cuando escribo estos datos en un archivo estoy usando la función sobrecargada < < que no sabe nada de datos reales y solo busca la terminación del segmento de datos.

Entonces, ¿cómo puedo decirle a la función de salida que escriba solo este número número específico de bytes?

En lugar de utilizar algo como esto que es caro llamar cada vez:

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 

} 

Respuesta

16

Si desea poner exactamente maxbytes bytes, utilice write método

stream.write(buffer, maxbytes); 

Si usted puede tener menos bytes en memoria intermedia, ¿cómo se sabe cuántos de ellos su memoria intermedia contiene? Si '\0' marcas tampón final, puede escribir:

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

En su segunda llamada, el segundo parámetro completo es solo una forma indirecta de llamar al antiguo simple 'strlen'. Pero en ese caso, también puede utilizar la forma más idiomática de toda la declaración: 'stream << buffer'. –

+0

No. strlen no se detendrá después de maxbytes. –

+0

'strnlen' will. Una llamada strnlen se verá mucho más limpia: 'strnlen (buffer, maxbytes)'. Sin perder el tiempo con punteros ni nada – gnud

3

Una solución barata sería tener un búfer que dispone de espacio para un carácter nulo adicional y sólo hay que poner un carácter nulo en el señale cuando conozca el tamaño real y luego envíe el búfer terminado en nulo como ya lo hace. Rápido y confiable.

+0

Sí, usted puede guardar ese personaje extra en una variable temporal. Una vez que se realiza la impresión, simplemente restaure. –

3

Esto funciona, pero no es seguro contra la llama accidentalmente la versión estándar de 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; 
} 

Esto es más seguro, utilizando un tipo maxw lo que limita la longitud de la siguiente char* salida:

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

El problema con strnlen es que AFAIK no es estándar. Y su función de plantilla es agradable, pero si un búfer se pasa como un puntero simple, no como una matriz, no habrá advertencia, solo se llamará a la función de salida de cadena c estándar. –

+0

Ha estado en C99 durante diez años, y IIRC C++ 0x traerá todos los estándares C99. –

+0

Bueno, busqué http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf y no pude encontrar strnlen. –

0

veo principalmente dos soluti ons.

En caso de datos ASCII:

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

entonces que siempre tenga cadena terminada en cero claro en buffor.

En segundo lugar, en caso de datos ASCII:

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

Si no se preocupan por el último byte, puede simplemente

buffer[buffersize-1] = 0; 

y luego alimentar buffer para cualquier función cadena que desea. Si es más corto, todo se ejecutará con el terminador nulo que ya existe, y si no hubiera terminador, se ejecutará con el que acaba de crear.

Y es rápido :)

Cuestiones relacionadas