【问题标题】:What is proper size of buffer when using sprint()?使用 sprint() 时缓冲区的正确大小是多少?
【发布时间】:2015-04-18 15:12:00
【问题描述】:

当我想使用 sprintf 函数时,char 数组(缓冲区)的正确大小是多少?

如果缓冲区只能容纳 1 个字符,我不知道为什么这部分代码可以工作?我在里面放了比 1 更多的字符。

/* sprintf example */
#include <stdio.h>

int main ()
{
    char buffer[1];
    int n, a=5, b=3;
    n = sprintf (buffer, "%d plus %d is %d", a, b, a+b);
    printf ("[%s] is a string %d chars long\n", buffer, n);
    return 0;
}

结果:

[5 plus 3 is 8] is a string 13 chars long

【问题讨论】:

  • 如果您使用 C++,您可以使用 std::stringstd::stringstream 类来完成此操作,而无需考虑内存要求。如果你必须使用sprintf,也许this question and its answers会帮助你。
  • 这个程序失控了! sprintf 函数正在将数据写入未分配的内存区域!当您使用 sprintf 时,您必须知道,或者您必须让程序能够计算出要使用的缓冲区的尺寸。为了避免内存边界问题,您可以使用处理缓冲区维度的 snprintf() 函数。
  • "buffer can only hold only 1 char" ...并且该char只能是'\0',因为buffer被认为是一个字符串;其他任何东西,当您使用 buffer 作为字符串时调用 UB (strlen(buffer), strcat(), ...)

标签: c++ c


【解决方案1】:

当我想使用 sprintf 函数时,char 数组(缓冲区)的正确大小是多少?

没有。

如果您可以从格式字符串和输入类型中计算出一个上限,那么您可以使用它。例如,一个 32 位的 int 不会占用超过 11 个字符来表示带有可选符号的十进制,因此您的特定示例不需要超过 44 个字符(除非我记错了)。

否则,请使用更安全的东西:在 C++ 中使用 std::stringstream,或者在 C 中使用 snprintf 和 care。

如果缓冲区只能容纳 1 个字符,我不知道为什么这部分代码可以工作?

不是。它正在将缓冲区末尾写入到其他内存中。

也许这不会导致任何可见的错误;也许它会破坏其他一些变量;可能会导致保护故障并结束程序;也许它会破坏堆栈帧并在函数试图返回时造成各种破坏;或者它可能会导致一些其他类型的未定义行为。但它的行为肯定不正确。

【讨论】:

    【解决方案2】:

    在您的代码中发生了缓冲区溢出,没有明显的后果,但这并不意味着它可以正常工作,尝试使用像 valgrind 这样的内存调试器,您就会明白我的意思了。

    您无法确保 sprintf() 不会溢出缓冲区,这就是为什么有一个 snprintf() 函数可以将缓冲区大小传递给该函数。

    示例用法

    char buffer[100];
    int  result;
    result = snprintf(buffer, sizeof(buffer), "%d plus %d is %d", a, b, a + b);
    if (result >= sizeof(buffer))
     {
        fprintf(stderr, "The string does not fit `buffer'.\n");
     }
    

    【讨论】:

      【解决方案3】:

      假设代码必须使用sprintf()而不是其他函数:
      预先确定最坏情况的输出大小并添加边距。

      除非存在重大内存问题,否则建议使用 2x 缓冲区。各种语言环境可以做一些有趣的事情,例如将',' 添加到整数输出中,如"123,456,789"

      #include <stdio.h>
      #include <limits.h>
      #define INT_DECIMAL_SIZE(i) (sizeof(i)*CHAR_BIT/3 + 3)
      
      #define format1 "%d plus %d is %d"
      char buffer[(sizeof format1 * 3 * INT_DECIMAL_SIZE(int)) * 2];
      int n = sprintf(buffer, format1, a, b, a + b);
      

      一个具有挑战性的例子是当代码尝试sprintf(buf,"%Lf", some_long_double),因为输出可能是1000个字符应该x == LDBL_MAX。大约 5000 个字符,binary128 为 long double。

      //                            -   123.............456   . 000000 \0
      #define LDBL_DECIMAL_SIZE(i) (1 + 1 + LDBL_MAX_10_EXP + 1   + 6   1)
      

      【讨论】:

        猜你喜欢
        • 2012-03-28
        • 1970-01-01
        • 2020-09-05
        • 2011-06-06
        • 2015-06-07
        • 2018-12-12
        • 2012-05-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多