Правильный способ определения буфера при использовании sprintf - PullRequest
0 голосов
/ 27 июня 2018

В моем наброске Arduino я использую sprintf для форматирования ответа. Отформатированные данные будут отправлены с использованием SPI.

Я должен установить длину буфера, но я не знаю, насколько большим будет хорошо. Вот кусок кода:

  uint8_t myValue = 4;

  // Set buffer
  unsigned char data[1000];
  // Reset this buffer
  memset(data, 0, sizeof(data));

  // Format the reply
  sprintf((char *)data, "This is the int value: %d", \
      myValue);

Я также могу установить буфер на 0 (unsigned char data[0];), код компилируется, и ответ такой же, как при использовании большого буфера. Я не могу это объяснить?

Кажется, malloc() и free() довольно редки в мире Arduino ...

Как правильно использовать буфер в Arduino?

Ответы [ 2 ]

0 голосов
/ 27 июня 2018

Я также могу установить буфер в 0 (беззнаковые данные [0];),

Если это правда, вам просто везет (или не везет, в зависимости от того, как вы на это смотрите). Поведение вашего кода при этом не определено как в C, так и в C ++. Что, помимо прочего, означает, что работа не гарантируется (например, он может сломаться, если ваш компилятор когда-либо будет обновлен).

Что касается лучших вариантов .... Ваш вопрос помечен C ++ и C, и для разных языков предпочтительнее разные подходы.

Если вы используете C и ваша реализация соответствует стандарту 1999 или более поздней версии, вы можете использовать snprintf().

  char *buffer;
  int length = snprintf((char *)NULL, 0, "This is the int value: %d",  myValue);
  buffer = malloc(length + 1);    /*   +1 allows for terminator */
  snprintf(buffer, length, "This is the int value: %d", myValue);

   /*  use buffer  */
  free(buffer);

Первый вызов sprintf() используется для восстановления длины буфера. Второй фактически записывает в выделенный буфер. Не забудьте освободить динамически распределенный буфер, когда закончите. (Вышеприведенное также не проверяет наличие ошибок - snprintf() возвращает отрицательное значение в случае возникновения ошибки).

Если ваша библиотека C не включает snprintf(), то (AFAIK) не существует стандартного способа автоматического определения длины - вам нужно будет вручную оценить верхнюю границу длины (например, определить длину вывода наибольшее отрицательное или положительное значение int, и добавьте его к длине другого содержимого в строке формата).

В C ++ используйте поток строк

 #include <sstream>
 #include <string>

 std::ostringstream oss;
 oss << "This is the int value: " << myValue);
 std::string str = oss.str();

 const char *buffer = str.data();

 //   readonly access to buffer here

 //   the objects above will be cleaned up when they pass out of scope.

Если вы настаиваете на использовании C-подхода в C ++, вышеуказанный подход с использованием snprintf() может быть использован в C ++, если ваша реализация соответствует стандарту 2011 (или более позднему). Однако, в общих чертах, я бы НЕ рекомендовал это.

0 голосов
/ 27 июня 2018

Я бы рекомендовал вместо этого использовать snprintf, где вы указываете размер буфера. При текущем подходе sprintf предполагает, что буфер достаточно велик, поэтому, если вы передадите ему небольшой буфер, он будет вытеснен из другой памяти. Не хорошо (и может объяснить странные результаты, которые вы иногда получаете)!

Вы можете использовать фиксированный буфер, как в вашем текущем коде. Распределение также работает, но имеет больше накладных расходов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...