Счетчик циклов PIC18F2550 перезаписан sprintf

У меня есть следующий код, скомпилированный с помощью компилятора Microchip MPLab и XC8 и работающий на PIC18F2550, который делает что-то довольно странное:

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);
}    

Цикл for выполняется только один раз, и во время этой итерации он правильно выполняет второй sprintf, но после его запуска значение iявляется чем-то случайным (26154, 8294,...). Я попытался заменить iдругую переменную, jприсваивающую значение ito jв начале цикла, но то же самое происходит и с i.

Кажется, что-то с этим sprintf, потому что, когда я использую отладчик, значение iне изменяется до тех пор, пока не sprintбудет выполнено. Следует отметить, что значение на выходе правильное (т. е. «Датчик 0 в настоящее время выключен \r\n»), что делает это еще более запутанным.

Это должен быть очень простой фрагмент кода, но он не работает, и я уверен, что этому есть простое объяснение. Где я должен искать?

Ответы (2)

Ваша проблема в этой строке:

char output[20];

Вы выделяете 20 символов для буфера для хранения вашей строки, а затем вызываете sprintf() для его заполнения.

Однако ваша строка формата слишком длинная, даже до включения десятичного значения. Помня, что последним элементом массива всегда должен быть \x00(символ NUL), у вас есть 19 символов для использования в вашем сообщении.

Подсчитайте количество символов в этой строке:

Датчик %d в настоящее время выключен\r\n

Всего 29 символов (при условии двузначного числа). Это приводит к переполнению буфера, что приводит к затиранию других переменных и может привести к тому, что ваша программа будет работать непредвиденным образом. Это один из распространенных типов проблем безопасности в C.

Увеличьте размер вашего буфера, чтобы он был достаточно большим, чтобы содержать:

  • все фиксированные буквы из вашего сообщения.
  • наибольшее число, которое iкогда-либо будет храниться в переменной.
  • отставание \r\n.
  • завершающий нулевой байт.
дох... Я знал, что это будет что-то простое. Спасибо!
Кроме того, если ваш компилятор поддерживает это, предпочтите snprintf() вместо sprintf().

Ваше char outputобъявление слишком маленькое для строки, которую вы хотите записать.

Попробуйте еще раз сchar output[50]

Ваша переменная count iсохраняется непосредственно за последней переменной массива символов.

Что-то вроде этого:

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

Теперь sprintf не проверяет длину массива, в который он записывает. Проверяйте длину массива перед записью в код!

два идеальных ответа, я хотел бы отметить оба как принятый ответ.