c++ conversion - Conversión de datos binarios a hex imprimible




5 Answers

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?

hexadecimal viceversa

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.




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?




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.




Related

c++ templates stl