Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Dar mas sencillez a este codigo

Estas en el tema de Dar mas sencillez a este codigo en el foro de C/C++ en Foros del Web. Hola amigos, he conseguido esta funcion la cual hace una especie de crc muy particular de un texto y quiero dejarlo lo mas simple posible ...
  #1 (permalink)  
Antiguo 26/10/2016, 16:20
 
Fecha de Ingreso: febrero-2015
Mensajes: 381
Antigüedad: 1 año, 10 meses
Puntos: 2
Dar mas sencillez a este codigo

Hola amigos, he conseguido esta funcion la cual hace una especie de crc muy particular de un texto y quiero dejarlo lo mas simple posible sin tantos castings ya que otras similares lo he conseguido y se que esta se puede pero no lo consigo. Aqui la funcion:
Código C++:
Ver original
  1. AnsiString CalcularValorLIC(char *cadena,int sizebuffer)
  2. {
  3.     signed char caracter;
  4.     unsigned long valor1, valor2, valor3, valor4;
  5.     unsigned long contador;
  6.     unsigned long sizefilelic;
  7.     unsigned long retval = 0;
  8.  
  9.     if (cadena) {
  10.         caracter = *cadena;
  11.         sizefilelic = 0;
  12.         if (caracter) {
  13.             do {
  14.                 if (caracter == 0x1A)
  15.                     break;
  16.                 caracter = *reinterpret_cast<signed char*>(sizefilelic + cadena + 1);
  17.                 ++sizefilelic;
  18.             } while (caracter);
  19.         }
  20.         contador = 0;
  21.         valor2 = 0;
  22.         valor3 = sizefilelic;
  23.         retval = valor3;
  24.         if (valor3) {
  25.             valor4 = valor3 + 1;
  26.             do {
  27.                 valor1 = static_cast<unsigned long>(*reinterpret_cast<unsigned char*>(contador + reinterpret_cast<unsigned long>(cadena)));
  28.                 valor2 = valor2 ^ valor1 + contador;
  29.                 ++contador;
  30.                 valor3 = (*reinterpret_cast<unsigned char*>(valor2 % valor4 + reinterpret_cast<unsigned long>(cadena) + 1) + valor2 + (valor1 + valor2) * 2 + retval) * valor2;
  31.                 retval = valor3;
  32.             } while (contador < sizefilelic);
  33.         }
  34.     }
  35.  
  36.     return AnsiString().sprintf("%09lu", retval);
  37. }
Lo que hace es recorrer un buffer y con una serie de operaciones obtiene la posicion de un byte con el que realizar mas operaciones e ir sumando y creando el crc.
He intentado quitarle los castings pero no doy con el modo y creo que lo hago mal y por eso da valores diferentes, porque no respeto correctamente el tema de los parentesis o algo asi.
¿podrian ayudarme a dejarlo lo mas claro posible para alguien como yo que no entiendo mucho de castings y cosas asi?
Por ejemplo esa parte si que se:
Código C++:
Ver original
  1. do {
  2.                 if (caracter == 0x1A)
  3.                     break;
  4.                 caracter = *reinterpret_cast<signed char*>(sizefilelic + cadena + 1);
  5.                 ++sizefilelic;
  6.             } while (caracter);
La dejo asi:
Código C++:
Ver original
  1. do {
  2.                 if (caracter == 0x1A)
  3.                     break;
  4.                 ++sizefilelic;
  5.                 caracter = cadena[sizefilelic];
  6.             } while (caracter);
Eso quiero hacer con todo el codigo para que sea lo mas sencillo para yo entenderlo.
Lo que me falta por modificar creo que tiene que quedar algo tal que asi:
Código C++:
Ver original
  1. *********** do {
  2. * * * * * * * * valor1 =cadena [contador];
  3. * * * * * * * * valor2 = valor2 ^ valor1 + contador;
  4. * * * * * * * * ++contador;
  5. * * * * * * * * valor3 = (cadena [(valor2 % valor4) + 1] + valor2 + (valor1 + valor2) * 2 + retval) * valor2;
  6. * * * * * * * * retval = valor3;
  7. * * * * * * } while (contador < sizefilelic);
Pero creo que hago algo mal.

Última edición por aguml; 26/10/2016 a las 17:06
  #2 (permalink)  
Antiguo 27/10/2016, 03:01
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 2 años, 3 meses
Puntos: 204
Respuesta: Dar mas sencillez a este codigo

Cambios que yo haría:

1. Reducir el ámbito de todas las variables

Así pasa que valor1...valor4 únicamente se usan en la segunda parte del algoritmo, no tiene sentido que estén declaradas al inicio de la función. Al inicio de la función únicamente deberían estar declaradas 1 variables: retval

2. Simplicar el tipo de las variables

caracter no gana nada siendo signed char. Lo cambio a char. Con este cambio tonto consigo que esto:

se convierta en esto:

Código C++:
Ver original
  1. caracter = cadena[sizefilelic + 1];

Con esto queda más claro que el bucle:

Código C++:
Ver original
  1. if (caracter) {
  2.   do {
  3.     if (caracter == 0x1A)
  4.       break;
  5.     caracter = cadena[sizefilelic + 1];
  6.     ++sizefilelic;
  7.   } while (caracter);
  8. }

3. Traducir el codigo a cristiano

Se puede simplificar bastante, ya que lo único que hace es contar caracteres hasta llegar al caracter 0x1A o al final del string. La versión simplificada podría quedar tal que:

Código C++:
Ver original
  1. char* ptr;
  2. for( *ptr = cadena ; *ptr && *ptr != 0x1A; ++ptr);
  3. unsigned long sizefilelic = ptr - cadena;

Y con C++11 y lambdas:

Código C++:
Ver original
  1. unsigned long sizefilelic = [cadena]()
  2. {
  3.   char* ptr;
  4.   for( *ptr = cadena ; *ptr && *ptr != 0x1A; ++ptr);
  5.   return ptr - cadena;
  6. }();

La segunda parte del algoritmo únicamente se ejecutará si valor3 es distinto de 0... puesto que valor3 coge su valor de sizefilelic podemos hacer que esa parte se ejecute únicamente si el valor de esta última variable es distinto de 0... quedará un código un poco más legible:
Código C++:
Ver original
  1. if( sizefilelic )
  2. {
  3.   unsigned long contador = 0;
  4.   unsigned long valor2 = 0;
  5.   unsigned long valor3 = sizefilelic;
  6.   retval = valor3;
  7.  
  8.   unsigned long valor4 = valor3 + 1;
  9.   do {
  10.     unsigned long valor1 = static_cast<unsigned long>(*reinterpret_cast<unsigned char*>(contador + reinterpret_cast<unsigned long>(cadena)));
  11.     valor2 = valor2 ^ valor1 + contador;
  12.     ++contador;
  13.     valor3 = (*reinterpret_cast<unsigned char*>(valor2 % valor4 + reinterpret_cast<unsigned long>(cadena) + 1) + valor2 + (valor1 + valor2) * 2 + retval) * valor2;
  14.     retval = valor3;
  15.   } while (contador < sizefilelic);
  16. }

Como el bucle do..while se va a ejecutar al menos una vez, la instrucción retval=valor3 se puede eliminar con todo el cariño del mundo.

Código C++:
Ver original
  1. valor1 = static_cast<unsigned long>(*reinterpret_cast<unsigned char*>(contador + reinterpret_cast<unsigned long>(cadena)));

Esta línea lo único que hace es desplazarse un offset dado por contador sobre el buffer cadena... lo único que almacena valor1 es el caracter existente en dicha posición convertido a unsigned long.

Un homólogo sencillo:

Código C++:
Ver original
  1. valor1 = static_cast<unsigned long>(cadena[contador]);

Esto:

Código C++:
Ver original
  1. *reinterpret_cast<unsigned char*>(valor2 % valor4 + reinterpret_cast<unsigned long>(cadena) + 1)

En cristiano significa esto:

Código C++:
Ver original
  1. cadena[(valor2%valor4) + 1];

Y para rematar la jugada, la variable contador la podemos meter en un for para sustituir el do-while, con lo que nos queda la segunda parte del algoritmo tal que:

Código C++:
Ver original
  1. if( sizefilelic )
  2. {
  3.   unsigned long valor2 = 0;
  4.   unsigned long valor3 = sizefilelic;
  5.  
  6.   const unsigned long valor4 = valor3 + 1;
  7.   for( unsigned long contador=0; contador<sizefilelic; ++contador)
  8.   {
  9.     unsigned long valor1 = static_cast<unsigned long>(cadena[contador]);
  10.     valor2 = valor2 ^ valor1 + contador;
  11.     valor3 = (cadena[(valor2%valor4) + 1] + valor2 + (valor1 + valor2) * 2 + retval) * valor2;
  12.     retval = valor3;
  13.   }
  14. }

No puedo probar el algoritmo primero porque no tengo ansistring y segundo porque no tengo cadenas de prueba... pero a grandes rasgos el código debería ser el mismo.

PD.: espero que si empiezas a sacar dinero de todo esto te acuerdes de mí jejejeje

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #3 (permalink)  
Antiguo 27/10/2016, 03:28
 
Fecha de Ingreso: febrero-2015
Mensajes: 381
Antigüedad: 1 año, 10 meses
Puntos: 2
Respuesta: Dar mas sencillez a este codigo

Jajaja dinero nada. Estas cosas las hago porque me gusta trastear y me divierte además de mantener la mente fresca. No soy universitario ni nada, simplemente me gusta y me divierte y me parece algo apasionante aunque me sobrepasa pero bueno.
Con respecto al ámbito de las variables, ciertamente es que primero aprendí C jejeje.
Ayer en el móvil estuve trasteando y llegue a algo parecido aunque los bucles siguen siendo do while y tampoco lo he probado:
Código C++:
Ver original
  1. AnsiString CalcularValorLIC(char *cadena,int sizebuffer)
  2. {
  3.     unsigned long valor1, valor2 = 0, valor3;
  4.     unsigned long contador = 0;
  5.     unsigned long sizefilelic = 0;
  6.     unsigned long retval = 0;
  7.  
  8.     do {
  9.         if (cadena[sizefilelic] == 0x1A)
  10.             break;
  11.         ++sizefilelic;
  12.     }while(cadena[sizefilelic]);
  13.  
  14.     valor3 = sizefilelic;
  15.     do {
  16.         valor1 = cadena [contador];
  17.         valor2 = valor2 ^ valor1 + contador;
  18.         retval = (cadena [(valor2 % (sizefilelic + 1)) + 1] + valor2 + (valor1 + valor2) * 2 + valor3) * valor2;
  19.         ++contador;
  20.     } while (contador < sizefilelic);
  21.     return AnsiString().sprintf("%09lu", retval);
  22. }
Yo directamente me cargue todos los castings ¿son realmente necesarios? El C++Builder no se queja nada.

Última edición por aguml; 27/10/2016 a las 03:38
  #4 (permalink)  
Antiguo 27/10/2016, 03:53
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 2 años, 3 meses
Puntos: 204
Respuesta: Dar mas sencillez a este codigo

Cita:
Iniciado por aguml Ver Mensaje
Con respecto al ámbito de las variables, ciertamente es que primero aprendí C jejeje.
Que conste que lo siguiente compila en C perfectamente:

Código C:
Ver original
  1. for( int i=0; i<10; i++)
  2.   printf("%d\n",i);

Cita:
Iniciado por aguml Ver Mensaje
Yo directamente me cargue todos los castings ¿son realmente necesarios? El C++Builder no se queja nada.
Habría que mirar cada caso individual ya que depende de cómo se gestionen los datos los cast pueden ser importantes.

Un ejemplo:

Código C++:
Ver original
  1. float a = 5;
  2. float b = 2;
  3. float res = static_cast<float>(static_cast<int>(a)/static_cast<int>(b)) + 1.0;

¿Se pueden quitar los cast?

Pues depende... el cast a float se puede eliminar, ya que el compilador realizará el cast automáticamente al sumar un entero con un float... pero si eliminas alguno de los cast a int entonces la división retornará decimales y el resultado no será el mismo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #5 (permalink)  
Antiguo 27/10/2016, 04:37
 
Fecha de Ingreso: febrero-2015
Mensajes: 381
Antigüedad: 1 año, 10 meses
Puntos: 2
Respuesta: Dar mas sencillez a este codigo

Bueno, tirando de tu codigo lo he dejado lo mas pequeño posible y haciendo pruebas da los mismos resultados que la original asi que asi la dejo:
Código C++:
Ver original
  1. AnsiString CalcularValorLIC(char *cadena,int sizebuffer)
  2. {
  3.     unsigned long resto = 0;
  4.     unsigned long retval = 0;
  5.  
  6.     for(int contador = 0; contador < sizebuffer; ++contador)
  7.     {
  8.         resto = resto ^ cadena[contador] + contador;
  9.         retval = (cadena[(resto % (sizebuffer + 1)) + 1] + resto + (cadena[contador] + resto) * 2 + retval) * resto;
  10.     }
  11.     return AnsiString().sprintf("%09lu", retval);
  12. }

Los cast aquí no son necesarios ya que funciona perfecto sin ellos.
El bucle que obtiene el tamaño del buffer no era necesario ya que ya introduzco el tamaño como parametro y la comprobación de cada caracter con 0x1A tampoco la necesito en mi caso porque todos serán caracteres imprimibles.
He quitado variables que no son necesarias para nada.
Un detalle, lo que tu dices que en C compila perfectamente a mi no me compila. Que yo sepa eso esta prohibido en C, se puede declarar variables al principio del ambito del for pero no en la estructura de creación de éste. No se si es porque eso cambio con alguna versión y yo tengo alguna anticuada pero ese es mi caso jejeje.
  #6 (permalink)  
Antiguo 27/10/2016, 04:47
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 2 años, 3 meses
Puntos: 204
Respuesta: Dar mas sencillez a este codigo

No tengo compiladores de C disponibles... pero hasta donde recuerdo el estándar C99 (que data de 1999) copió de C++ la posibilidad de declarar variables en cualquier parte del código... incluídos los bucles.

Lo mismo deberías actualizar tu compilador.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #7 (permalink)  
Antiguo 27/10/2016, 16:23
 
Fecha de Ingreso: febrero-2015
Mensajes: 381
Antigüedad: 1 año, 10 meses
Puntos: 2
Respuesta: Dar mas sencillez a este codigo

La verdad es que no se que compilador tengo y no se como verlo pero es el que trae C++Builder 6.
  #8 (permalink)  
Antiguo 28/10/2016, 01:33
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 2 años, 3 meses
Puntos: 204
Respuesta: Dar mas sencillez a este codigo

En el diálogo "acerca de" del IDE te podrás hacer una idea de la fecha del compilador... que imagino que por tu versión rondará el año 2000.

En cualquier caso, C++ Builder está pensado sobretodo para el desarrollo de programas en C++...
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #9 (permalink)  
Antiguo 29/10/2016, 01:02
 
Fecha de Ingreso: febrero-2015
Mensajes: 381
Antigüedad: 1 año, 10 meses
Puntos: 2
Respuesta: Dar mas sencillez a este codigo

Ok gracias.



La zona horaria es GMT -6. Ahora son las 13:07.