Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Parser hexadecimal - CordayUK

Iniciado por ethernet, 23 de Febrero de 2003, 05:28:07 PM

« anterior - próximo »

ethernet

    Parser hexadecimal


    A ver si animamos un poco el Codigo de la Semana que esta muy aburido ultimamente

    mando este trozo de codigo que estuve escribiendo el otro dia, del cual no estoy muy contento porque estoy seguro que se puede hacer mejor... si alguien se anima que me de su version mejorada y se lo agradecere enormemente con mujeres y vino XDDD

    la idea es convertir una cadena que representa un DWORD en una variable DWORD propiamente dicha.
    Esto es muy util cuando tienes un fichero de ascii con valores que quieres introducir en tu juego, digamos un fichero INI, XML o lo que sea...

    FOG_COLOR = FFAAAA11

    al leer el fichero obtenemos una cadena "FFAAAA11" pero queremos meter este valor en un DWORD para pasarselo a DX por ejemplo.





typedef unsigned long DW;   //es lo mismo que el DWORD definido en windows.h



inline unsigned char __CHAR2BYTE (unsigned char c)

{

  switch (c)

  {

     case '0': return 0x0;

     case '1': return 0x1;

     case '2': return 0x2;

     case '3': return 0x3;

     case '4': return 0x4;

     case '5': return 0x5;

     case '6': return 0x6;

     case '7': return 0x7;

     case '8': return 0x8;

     case '9': return 0x9;

     case 'A': return 0xA;

     case 'B': return 0xB;

     case 'C': return 0xC;

     case 'D': return 0xD;

     case 'E': return 0xE;

     case 'F': return 0xF;

  }

  return 0x0;

}



DW GetValueDW (char* pszValue)

{

DW dw = 0x00000000;





  //comprobar cadena

  if (!pszValue || strlen (pszValue)<8) return dw;



  //meter en el dword cada char de la cadena

  for (short int i=0; i<8; i++)

     dw = dw | (0x00000000 | __CHAR2BYTE (*(pszValue+i))<< (28-(i*4)));



  return dw;

}








    Éste código fue enviaro por CordayUK.
    Si quieres enviar tu propio código puedes hacerlo a
eth_cotw@lycos.es

    fiero

                                    Yo propondria un par de mejoras.

    Que la función __CHAR2DW devuelva un DW, para evitarnos después la conversión (eso de hacer un | 0x00000000).

    También almacenar la longitud de la cadena para poder convertir cadenas más cortas. Por ejemplo, poder escribir en el archivo "AABB" en vez de "0000AABB", si queremos guardar el numero 0x0000AABB

    un saludo

    typedef unsigned long DW;   //es lo mismo que el DWORD definido en windows.h



    inline DW __CHAR2DW (unsigned char c)

    {

      switch (c)

      {

         case '0': return 0x0;

         case '1': return 0x1;

         case '2': return 0x2;

         case '3': return 0x3;

         case '4': return 0x4;

         case '5': return 0x5;

         case '6': return 0x6;

         case '7': return 0x7;

         case '8': return 0x8;

         case '9': return 0x9;

         case 'A': return 0xA;

         case 'B': return 0xB;

         case 'C': return 0xC;

         case 'D': return 0xD;

         case 'E': return 0xE;

         case 'F': return 0xF;

      }

      return 0x0;

    }



    DW GetValueDW (char* pszValue)

    {

      DW dw = 0x00000000;

      int num;



      //comprobar cadena

      if (!pszValue || (num=strlen (pszValue))>8) return dw;



      //meter en el dword cada char de la cadena

      for (int i=0; i<num; i++)

         dw = dw | __CHAR2DW(pszValue[i]) << ((num-i-1)*4);



      return dw;

    }
                                   
    www.videopanoramas.com Videopanoramas 3D player

    Juan Mellado

    El uso de los índices dentro del bucle se puede simplificar un poco:



      for (int i = 0; i<num; ++i)

         dw = (dw << 4) | __CHAR2DW(pszValue[i]);


    fiero

                                    Ahá! , en cierto modo, es más lógico ir desplazando el resultado como  FIFO y meter el siguiente dígito siempre en la 1º posición. Si es que a veces nos complicamos la vida.... :)

    un saludo                                
    www.videopanoramas.com Videopanoramas 3D player

    Zaelsius

                                    Bueno, pues aquí está mi version de la rutina SUPER-OPTIMIZADA  :D





    // Aquí está la clave :-D



    #define __CHAR2BYTE(c)    ((c) >= '0' && (c) <= '9' ? (c) - '0' : (c) - 55 )



    DWORD GetValueDW (char* pszValue)

    {

    DWORD dw = 0x00000000;



    if (!pszValue || strlen (pszValue)<8) return dw;



    // Bucle desenrrollado

    dw = dw |  __CHAR2BYTE (*(pszValue))<< (28);

    dw = dw |  __CHAR2BYTE (*(pszValue+1))<< (24);

    dw = dw |  __CHAR2BYTE (*(pszValue+2))<< (20);

    dw = dw |  __CHAR2BYTE (*(pszValue+3))<< (16);

    dw = dw |  __CHAR2BYTE (*(pszValue+4))<< (12);

    dw = dw |  __CHAR2BYTE (*(pszValue+5))<< (8);

    dw = dw |  __CHAR2BYTE (*(pszValue+6))<< (4);

    dw = dw |  __CHAR2BYTE (*(pszValue+7));



    return dw;

    }





    ¡A ver que tal os parece!                                

    fiero

                                    Todavia se puede optimizar más  :ojo: :

    #define __CHAR2BYTE(c)    ((c) > '9' ? (c) - 'A' : (c) - '0' )

    un saludo                                
    www.videopanoramas.com Videopanoramas 3D player

    Zaelsius

    Joer fiero, no me has dejado ni editar el post en un momento....XD
    ¿Pues quedaría algo así, no?



    // Mega optimized XD

    #define __CHAR2BYTE(c)    ((c) > '9' ? (c) - 'A' : (c) - '0' )



    DWORD GetValueDW (char* pszValue)

    {

    DWORD dw = 0x00000000;



    if (!pszValue || strlen (pszValue)<8) return dw;



    dw = (dw << 4) |  __CHAR2BYTE (pszValue[0]);

    dw = (dw << 4) |  __CHAR2BYTE (pszValue[1]);

    dw = (dw << 4) |  __CHAR2BYTE (pszValue[2]);

    dw = (dw << 4) |  __CHAR2BYTE (pszValue[3]);

    dw = (dw << 4) |  __CHAR2BYTE (pszValue[4]);

    dw = (dw << 4) |  __CHAR2BYTE (pszValue[5]);

    dw = (dw << 4) |  __CHAR2BYTE (pszValue[6]);

    dw = (dw << 4) |  __CHAR2BYTE (pszValue[7]);



    return dw;

    }


    fiero

                                    ups, perdón ZaelSiuS, mi  - 'A' está mal, tu -55 primero está bien                                
    www.videopanoramas.com Videopanoramas 3D player

    CordayUK

                                    Donde os mando las mujeres y el vino?????? XDDDDD

    muchas gracias, me mola la optimizacion. Ya sabia yo que se podia hacer mejor!!! thx                                

    Zaelsius

    Y ya para rematar el COTW me he marcado un pequeño programa que testea las dos funciones(original y optimizada).

    Lo podeis bajar de aquí:
    http://www.alu.ua.es/j/jgf8/files/download...d/getdwtest.zip

    A mí me saca un 520% de rendimiento más la funcion optimizada( en un Athlon 1600+).

    El código de test es casi todo de un artículo de Game Programming Gems 2.

    ¡Que aproveche!

    ethernet

    No rularia mas rapido con una tabla asi ->

    char tabla[256];

    tabla['1'] = 1;
    tabla['2'] = 2;
    ..
    ..
    tabla['A'] = 10;

    desperdicias memoria pero mola XD.
    Despues de hacer eso usar

    #define __CHAR2BYTE©    tabla[c];



    es una idea, quizas sea mas rapido hacer lo q haceis vosotros q usar la memoria para ello.

    NOTA: las funciones q proponeis NO hacen los mismo q la de corday...
    EDIT: error, mire el codigo de fiero del numero de caracteres exacto 0:DDD, lo siento XD

    saludos

    ethernet

    Ejem, he mirado el codigo para probar la rapidez y no seria mejor tener:

    __int64 cuentatiempo(void (*fn)(dword )); ?

    el programa de contar el tiempo si  q lo optimizaba yo XDD

    saludos

    Juan Mellado

                                    Je, je, como nos picamos.  :D

    Ethernet, lo de las tablas está bien para CPUs sin problemas de caché y todas esas cosistas.

    "Ofuscando" un poco el código se evita además las rotaciones:



    unsigned char odd[]  = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,

                           0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

                           0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};



    unsigned char even[] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,

                           0x80, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

                           0x00, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0};



    #define __CHAR_ODD(c)  ( (odd - '0')[c])

    #define __CHAR_EVEN(c) ( (even -'0')[c])



    DWORD GetValueDW(char * pszValue)

    {

      DWORD dw = 0x00000000;

     

      if ( !pszValue || strlen(pszValue) < 8) return dw;



      ( (char *)(&dw) )[3] = __CHAR_EVEN(pszValue[0]) | __CHAR_ODD(pszValue[1]);

      ( (char *)(&dw) )[2] = __CHAR_EVEN(pszValue[2]) | __CHAR_ODD(pszValue[3]);

      ( (char *)(&dw) )[1] = __CHAR_EVEN(pszValue[4]) | __CHAR_ODD(pszValue[5]);

      ( (char *)(&dw) )[0] = __CHAR_EVEN(pszValue[6]) | __CHAR_ODD(pszValue[7]);

       

      return dw;

    }



    El siguiente paso podría ser crear tablas con WORD y DWORD desplazando un byte cada vez.  Pero no merece la pena dedicarle más tiempo, como se suele decir: "hay que preocuparse en optimizar lo que realmente necesite ser optimizado". Aunque dedicarle un rato a pesar en cosas como esta es divertido, ¿verdad?.

    Venga, buenas noches                                

    fiero

                                   
    CitarAunque dedicarle un rato a pesar en cosas como esta es divertido, ¿verdad?.

    Si, divertido e instructivo, por eso es recomendable empezar a hacer comecocos y cosas así en modo texto, porque se aprende realmente a programar con estas cosas sencillitas...

    un saludo                                
    www.videopanoramas.com Videopanoramas 3D player

    ethernet

    Muy c00l el ecodigo juan, q procesadores tienen problemas de cpu actualmente, en cuales no entran 256 bytes? o menos en el caso de tus tablas.
    de todas maneras dudo cual de los metodos es mas rapido, si el de las tablas o el propuesto por zaelsius,

    pd: todavia me estoy tirando de los pelos del codigo para probar la velocidad ... los de programming gems no tienen ni zorra de lo q es diseñar o q? XD

    saludos






    Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
    Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
    Muchísimas gracias.