Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: huchoko en 6 Abril 2019, 15:24 pm



Título: Implementación de printf no termina con null las cadenas
Publicado por: huchoko en 6 Abril 2019, 15:24 pm
Buenas, he hecho una implementación de printf, sin usar vsnprintf (por que no puedo).
Funciona bien, pero si trato de formatear un número hexadecimal y aveces cadenas, se descontrola todo, por lo que pienso que se me está colando un terminador nulo '\0' .
Ejemplo:
Código
  1. kputs("r8: %x    r9: %x    r10: %x", r->r8, r->r9, r->r10);
Salida:
Código:
r8: b8000└
Sólo me imprime r8  y de ahí el valor en hexadecimal, pero los demás los ignora y no imprime r9 ni r0.
Nótese el carácter "└" el cual no es esperado.
Código
  1. int kputs(const char *fmt, ...) {
  2. /* Hacer nada si la cadena esta vacia. */
  3. if (!fmt)
  4. return 0;
  5. char buffer[1024] = {0};
  6. va_list args;
  7.  
  8. size_t cout;
  9. unsigned int* charc;
  10. va_start(args, fmt);
  11.  
  12. for (cout = 0; cout < strlen(fmt); ++cout) {
  13. switch (fmt[cout]) {
  14. case '%':
  15. switch (fmt[cout + 1]) {
  16. case 'c':
  17. charc = va_arg(args, unsigned int);
  18. putch(charc);
  19. ++cout;
  20. break;
  21. case 's':
  22. charc = (int*) (va_arg(args, unsigned int));
  23. strcpy(buffer, (const char*) charc);
  24. print_string(buffer);
  25. ++cout;
  26. break;
  27. case 'i':
  28. charc = va_arg(args, int);
  29. itoa(charc, buffer, 10);
  30. print_string(buffer);
  31. ++cout;
  32. break;
  33. case 'X':
  34. case 'x':
  35. charc = va_arg(args, int);
  36. itoa((unsigned)charc, buffer, 16);
  37. print_string(buffer);
  38. ++cout;
  39. case '%':
  40. putch("%");
  41. ++cout;
  42.  
  43. default:
  44. va_end(args);
  45. return 1;
  46. }
  47. break;
  48. default:
  49. putch(fmt[cout]);
  50. break;
  51. }
  52. }
  53. va_end(args);
  54. return cout;
  55. }
  56.  
Las funciones itoa no creo que sean el problema, por que mi implementación no tiene problemas para imprimir enteros. (excepto que se desborda con un número muy grande, eso se arregla fácil)


Título: Re: Implementación de printf no termina con null las cadenas
Publicado por: CalgaryCorpus en 7 Abril 2019, 01:13 am
Tienes que variar el tipo del segundo parametro de va_arg.

Tu solo usas unsigned int (o int) y deberias usar el tipo que calce con el % que se pasa.

Mira el ejemplo al final de aqui: https://linux.die.net/man/3/va_arg


Título: Re: Implementación de printf no termina con null las cadenas
Publicado por: huchoko en 7 Abril 2019, 04:49 am
Tienes que variar el tipo del segundo parametro de va_arg.

Tu solo usas unsigned int (o int) y deberias usar el tipo que calce con el % que se pasa.

Mira el ejemplo al final de aqui: https://linux.die.net/man/3/va_arg

Gracias, pero aún así no me funciona, mismo problema.  :-(


Título: Re: Implementación de printf no termina con null las cadenas
Publicado por: CalgaryCorpus en 7 Abril 2019, 05:50 am
Muestra el codigo modificado


Título: Re: Implementación de printf no termina con null las cadenas
Publicado por: huchoko en 7 Abril 2019, 14:46 pm
Mismo problema, hacer un cast de int a char cuando trato de imprimir hexadecimal no imprime nada, y el mismo problema...

Código
  1. int kputs(const char *fmt, ...) {
  2. /* Empty string sanity test */
  3. if (!fmt)
  4. return 0;
  5. char buffer[1024] = {0};
  6. va_list args;
  7.  
  8. size_t cout;
  9. unsigned int* charc;
  10. va_start(args, fmt);
  11.  
  12. for (cout = 0; cout < strlen(fmt); ++cout) {
  13. switch (fmt[cout]) {
  14. case '%':
  15. switch (fmt[cout + 1]) {
  16. case 'c':
  17. charc = (char)va_arg(args, int);
  18. putch(charc);
  19. ++cout;
  20. break;
  21. case 's':
  22. charc = va_arg(args, char *);
  23. strcpy(buffer, (const char*) charc);
  24. print_string(buffer);
  25. ++cout;
  26. break;
  27. case 'i':
  28. charc = va_arg(args, int);
  29. itoa(charc, buffer, 10);
  30. print_string(buffer);
  31. ++cout;
  32. break;
  33. case 'X':
  34. case 'x':
  35. charc = (char)va_arg(args, int);
  36. itoa(charc, buffer, 16);
  37. print_string(buffer);
  38. ++cout;
  39. case '%':
  40. putch("%");
  41. ++cout;
  42.  
  43. default:
  44. va_end(args);
  45. return 1;
  46. }
  47. break;
  48. default:
  49. putch(fmt[cout]);
  50. break;
  51. }
  52. }
  53. va_end(args);
  54. return cout;
  55. }


Título: Re: Implementación de printf no termina con null las cadenas
Publicado por: CalgaryCorpus en 7 Abril 2019, 16:05 pm
sugiero que recibas lo que va_arg te retorna en una variable del tipo que pides.

Ejemplo en linea 28 y siguientes:

cambia por

Código
  1.  int miVariableInt;  // al inicio de la funcion
  2.  
  3. // y luego en el switch, para el caso .'i'
  4.  miVariableInt = va_arg(args, int);
  5.  itoa(miVariableInt, buffer, 10);
  6.  print_string(buffer);

Y si esto se comporta bien, hacer los mismos con los otros tipos.


Título: Re: Implementación de printf no termina con null las cadenas
Publicado por: huchoko en 7 Abril 2019, 22:53 pm
Ahora si funciona para los enteros, pero aún está el problema con los hexadecimales.
Osea, si le paso el hexadecimal 0xF2, imprime 0xF2, pero no tiene el terminador nulo, lo cual hace que se imprima un caracter aleatorio después de imprimir el hexadecimal. (Sólo pasa cuando se trata de imprimir hexadecimal, los demás están ok)


Título: Re: Implementación de printf no termina con null las cadenas
Publicado por: RayR en 8 Abril 2019, 01:20 am
Ese error se debe a que te falta un break para el case 'x' (y ya que estamos, para el case '%').

Hay más problemas, pero el principal es lo que ya te dijeron, que debes usar variables de distintos tipos según el % que recibas. Tal como lo tienes es una suerte que funcione.

Dado que char c es un puntero, cuando se ejecuta esto:

Código:
charc = va_arg(args, int);

Lo que en realidad estás haciendo es que charc apunte a la dirección de memoria cuyo número le enviaste a kputs. Por ejemplo, si le envias 22, charc estará apuntando a la dirección 22. Cuando llamas a itoa, en realidad le estás pasando una dirección de memoria, pero como esta función espera un simple entero, lo interpreta como tal, y por eso no falla. Pero si en algún punto se intentara desreferenciar a charc, tu programa fallaría estrepitosamente  ;D, seguramente generando una violación de acceso. charc debería ser un simple int, o unsigned, y para el case 's' debes usar un char *.


Título: Re: Implementación de printf no termina con null las cadenas
Publicado por: huchoko en 8 Abril 2019, 03:29 am
Gracias, funciona perfectamente! Gracias a ambos!
Ese error se debe a que te falta un break para el case 'x' (y ya que estamos, para el case '%').
Ah, ¡esos condenados break! siempre me pasa, y por más que reviso el código siempre se me cola uno  ;-)
Saludos  :)