valor - programa en c++ que convierta de decimal a binario y viceversa
Conversión de datos binarios a hex imprimible (9)
En este hilo, alguien comentó que el siguiente código solo debería usarse en proyectos de ''juguetes''. Desafortunadamente, él no ha regresado para decir por qué no es de calidad de producción, así que esperaba que alguien en la comunidad pudiera asegurarme que el código está bien (porque me gusta bastante) o identificar qué está mal.
template< class T1, class T2>
void hexascii( T1& out, const T2& in )
{
out.resize( in.size() * 2 );
const char hexDigits[] = {''0'', ''1'', ''2'', ''3'', ''4'', ''5'', ''6'', ''7'',''8'', ''9'', ''A'', ''B'', ''C'', ''D'', ''E'', ''F''};
T1::iterator outit = out.begin();
for( T2::const_iterator it = in.begin(); it != in.end(); ++it )
{
*outit++ = hexDigits[*it >> 4];
*outit++ = hexDigits[*it & 0xF];
}
}
template<class T1, class T2>
void asciihex( T1& out, const T2& in )
{
size_t size = in.size;
assert( !(size % 2) );
out.resize( size / 2 );
T1::iterator outit = out.begin();
for( T2::const_iterator it = in.begin(); it != in.end(); it += 2, ++outit )
{
*outit = ((( (*it > ''9'' ? *it - 0x07 : *it) - 0x30) << 4) & 0x00f0) +
(((*(it+1) > ''9'' ? *(it+1) - 0x07 : *(it+1)) - 0x30) & 0x000f);
}
}
Editar: Gracias por su ayuda chicos, han hecho algunas mejoras importantes. He escrito funciones en los dos estilos sugeridos de sus respuestas. Algunas pruebas preliminares sugieren que el segundo método es marginalmente más rápido que el primero, pero el IMO se ve superado por la legibilidad mejorada del primero.
template<class T1>
void asciihex2( T1& out, const std::string& in )
{
dassert( sizeof(T1::value_type)==1 );
size_t size = in.size();
assert( !(size % 2) );
out.resize( size / 2 );
T1::iterator outit = out.begin();
for( size_t i = 0; i < in.size(); i += 2 )
{
int tmp;
sscanf( in.c_str() + i, "%02X", &tmp );
*outit++ = tmp;
}
}
template<class T1>
void asciihex3( T1& out, const std::string& in )
{
dassert( sizeof(T1::value_type)==1 );
size_t size = in.size();
assert( !(size % 2) );
out.resize( size / 2 );
T1::iterator outit = out.begin();
const char hexDigits[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
for( std::string::const_iterator it = in.begin(); it != in.end(); it += 2, ++outit )
{
*outit = (hexDigits[(*it - 0x30) & 0x1f] << 4) +
hexDigits[((*(it+1) - 0x30) & 0x1f)];
}
}
Algunas de las suposiciones que rodean este código: 1: no están pensadas como genéricas, sino que se usan en un espacio de nombre anónimo para traducir datos para una clase específica. 2: Se requiere la creación de plantillas ya que se están utilizando dos tipos de contenedores separados (uno siendo std :: vector, y el otro un contenedor de tipo de matriz de bytes similar de una biblioteca de terceros. 3: El propósito es poder convertir datos binarios de indeterminado longitud en cadenas y viceversa (0x1234abcd <-> "1234abcd") 4: cometer errores de trampas tanto en los modos de depuración como de liberación 5: cuando estas funciones se llaman el tamaño de la cadena ya habrá sido verificado, se usa assert para terminar el procesamiento si algo serio ha salido mal 6: Necesita algunos comentarios
Cualquier otra idea apreciada.
¿Qué se supone que haga? No existe un significado aceptado bien conocido de hexascii o asciihex, por lo que los nombres deberían cambiar.
[edit] La conversión de la notación binaria a la hexadecimal a menudo no se debe llamar ascii ..., ya que ascii es un formato de 7 bits.
Algunos problemas que veo:
Esto funcionará muy bien si solo se utiliza para un contenedor de entrada que almacena tipos de 8 bits, por ejemplo, char o char sin signo. Por ejemplo, el siguiente código fallará si se usa con un tipo de 32 bits cuyo valor después del desplazamiento a la derecha sea mayor que 15: recomiéndele que siempre use una máscara para asegurarse de que el índice de búsqueda esté siempre dentro del rango.
*outit++ = hexDigits[*it >> 4];
¿Cuál es el comportamiento esperado si pasa en un contenedor que contiene longs sin firmar? Para que esta sea una clase genérica, probablemente debería ser capaz de manejar la conversión de números de 32 bits a hext strings también.
Esto solo funciona cuando la entrada es un contenedor. ¿Qué sucede si solo quiero convertir un solo byte? Una sugerencia aquí es refactorizar el código en una función central que puede encubrir un solo byte (hex => ascii y ascii => hexadecimal) y luego proporcionar funciones adicionales para usar esta función central para covertir contenedores de bytes, etc.
En asciihex (), sucederán cosas malas si el tamaño del contenedor de entrada no es divisible por 2. El uso de:
it != in.end(); it += 2
es peligroso ya que si el tamaño del contenedor no es divisible por 2, entonces el incremento en dos avanzará el iterador más allá del final del contenedor y la comparación con el extremo () nunca funcionará. Esto está de alguna manera protegido a través de la llamada afirmativa, pero la afirmación puede compilarse (por ejemplo, a menudo se compila en compilaciones de versiones) por lo que sería mucho mejor hacer de esto una declaración if.
La razón por la que lo consideraría código de juguete es que no hay verificación de errores.
Podría pasarle dos vectores y felizmente intentaría hacer algo y crearía un lío completo generando un galimatías aleatorio.
Mi principal comentario al respecto es que es muy difícil de leer.
Especialmente:
*outit = ((( (*it > ''9'' ? *it - 0x07 : *it) - 0x30) << 4) & 0x00f0) +
(((*(it+1) > ''9'' ? *(it+1) - 0x07 : *(it+1)) - 0x30) & 0x000f)
A mi cerebro le tomaría un tiempo asimilar eso y molestarme si heredé el código.
Parece que una gran cantidad de código de plantilla para lograr muy poco, dado que tiene conversión hexadecimal directa en las funciones estándar C scanf y printf . ¿por qué molestarse?
Problemas que veo:
hexascii no comprueba si sizeof(T2::value_type)==1
hexascii it
desclasifica dos veces, asciihex aún más. No hay ninguna razón para esto, ya que puedes almacenar el resultado. Esto significa que no puede usar istream_iterator.
asciihex necesita un iterador aleatorio como entrada, porque (it + 1) y (it + = 2) se usan. El algoritmo podría funcionar en un iterador directo si solo usa (++ it).
(*it > ''9'' ? *it - 0x07 : *it) - 0x30
se puede simplificar a *it - (*it > ''9'' ? 0x37 : 0x30)
por lo que solo queda una resta incondicional. Aún así, una búsqueda de matriz sería más eficiente. Reste 0x30. ''0'' se convertirá en 0; ''A'' se convertirá en 0x11 y ''a'' se convertirá en 0x31. Enmascare con 0x1f para que no distinga entre mayúsculas y minúsculas, y puede hacer la búsqueda resultante en un carácter [0x20] sin riesgos de desbordamiento. Los caracteres no hexagonales solo te darán valores extraños.
Qué hay de malo en
*outit = hexDigits[*it]
¿Por qué estas dos funciones no pueden compartir una lista común de hexDigits y eliminar el cálculo complejo (y lento) de un carácter ASCII?
El código tiene declaraciones de afirmación en lugar de un manejo correcto de una condición de error (y si su afirmación está desactivada, el código puede explotar)
para el ciclo tiene un doble aumento peligroso del iterador (it + = 2). Especialmente en caso de que su afirmación no se dispare. ¿Qué sucede cuando tu iterador ya está al final y tú ++?
El código está modelado, pero lo que estás haciendo es simplemente convertir personajes en números o al revés. Es programación de culto a la carga . Esperas que las bendiciones de la programación de plantillas te lleguen mediante el uso de plantillas. Incluso etiquetó esto como una pregunta de plantilla aunque el aspecto de la plantilla es completamente irrelevante en sus funciones.
el * outit = línea es demasiado complicado.
el código reinventa la rueda. A lo grande.
Realmente no me opongo. Es genérico (dentro de los límites), usa constelaciones, referencias cuando es necesario, etc. Falta documentación y la asignación de *outit
asciihex
*outit
no es muy clara a primera vista.
resize
el resize
inicializa los elementos de salida innecesarios (use reserve
lugar).
Tal vez la genérico es algo demasiado flexible: puedes alimentar los algoritmos con cualquier tipo de datos que desees, mientras que solo deberías darle números hexadecimales (no por ejemplo, un vector
de double
)
Y de hecho, puede ser un poco exagerado , dada la presencia de buenas funciones de la biblioteca.