Contador de bucle PIC18F2550 sobrescrito por sprintf

Tengo el siguiente código compilado con el compilador MPLab y XC8 de Microchip y ejecutándose en un PIC18F2550 que está haciendo algo bastante extraño:

char output[20];
int i = 0;

char currentStatus = readShiftReg();
for (i = 0; i < 8; i++) {
    if ((currentStatus & (1 << i)) == (1 << i))
        sprintf(output, "Sensor %d is currently on \r\n", i + 1);
    else
        sprintf(output, "Sensor %d is currently off \r\n", i + 1);
    putsUSART(output);
}    

El ciclo for solo itera una vez y durante esa iteración ejecuta correctamente el segundo sprintf, pero después de ejecutarlo, el valor de ies algo aleatorio (26154, 8294, ...). Intenté cambiar ipor otra variable jasignando el valor de ito jal comienzo del ciclo, pero todavía sucede lo mismo con i.

Parece que es algo sprintfporque cuando uso el depurador, el valor de ino cambia hasta después de sprintlas ejecuciones. Una cosa a tener en cuenta es que el valor en la salida es correcto (es decir, "El sensor 0 está actualmente apagado \r\n") lo que hace que esto sea aún más desconcertante.

Esto debería ser una pieza de código muy simple, pero no funciona y estoy seguro de que hay una explicación simple. ¿Dónde debería estar buscando?

Respuestas (2)

Tu problema es esta línea:

char output[20];

Está asignando 20 caracteres para que el búfer contenga su cadena, luego llama a sprintf() para llenarlo.

Sin embargo, su cadena de formato es demasiado larga, incluso antes de que se incluya el valor decimal. Recordando que el último elemento de la matriz siempre deberá ser \x00(un carácter NUL), tiene 19 caracteres para usar en su mensaje.

Cuente el número de caracteres en esta cadena:

El sensor %d está actualmente apagado \r\n

Hay 29 caracteres (asumiendo un número de dos dígitos). Esto da como resultado un desbordamiento del búfer, que comenzará a aplastar otras variables y puede hacer que su programa funcione de manera inesperada. Es un tipo común de problema de seguridad en C.

Aumente el tamaño de su búfer para que sea lo suficientemente grande como para contener:

  • todas las letras fijas de su mensaje.
  • el número más grande que la variable ijamás tendrá.
  • el arrastre \r\n.
  • el byte NUL de terminación.
doh... Sabía que sería algo simple. ¡Gracias!
Además, si su compilador lo admite, prefiera snprintf() sobre sprintf().

Su char outputdeclaración es demasiado pequeña para la cadena que desea escribir.

Inténtalo de nuevo conchar output[50]

Su variable de recuento ise guarda directamente detrás de la última variable de la matriz de caracteres.

Algo como esto:

Adress       Value
0x0F00      char[0]
0x0F01      char[1]
  .           .
  .           .
  .           .
0x0F19      char[19]   <-- last variable of char
0x0F20      i          <-- counter variable

Ahora sprintf no verifica la longitud de la matriz en la que escribe. ¡Compruebe la longitud de la matriz antes de escribirla en el código!

dos respuestas perfectas, desearía poder marcar ambas como la respuesta aceptada.