使用sprintf时定义缓冲区的正确方法

时间:2018-06-27 09:00:52

标签: c++ arduino

在我的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];),代码将编译,并且答复与使用大缓冲区相同。我无法解释吗?

在Arduino世界中,malloc()free()似乎很少见。

在Arduino中使用缓冲区的正确方法是什么?

2 个答案:

答案 0 :(得分:1)

我建议改为使用snprintf,在其中指定缓冲区的大小。使用当前方法,sprintf假定缓冲区足够大,因此,如果将其传递给较小的缓冲区,它将占用其他一些内存。不好(可能会解释您有时会得到的奇怪结果)!

您可以像当前代码一样使用固定缓冲区。分配也可以,但是开销更大。

答案 1 :(得分:0)

  

我还可以将缓冲区设置为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方法,那么如果您的实现符合2011标准(或更高版本),则可以在C ++中使用上面使用snprintf()的方法。但是,总的来说,我不建议这样做。