确定sprintf缓冲区大小 - 标准是什么?

Dom*_*mra 43 c int printf

像这样转换int时:

char a[256];
sprintf(a, "%d", 132);
Run Code Online (Sandbox Code Playgroud)

什么是确定如何大的最好方式一个应该是什么?我假设手动设置它很好(因为我看到它在任何地方使用),但它应该有多大?在32位系统上可能的最大int值是多少,是否有一些棘手的方法来确定它?

Dan*_*age 77

有些人认为这种方法有点过分,而且对于将int转换为字符串,我可能更倾向于同意.但是当找不到合理的字符串大小限制时,我已经看到了这种方法并且自己使用了它.

int size = snprintf(NULL, 0, "%d", 132);
char * a = malloc(size + 1);
sprintf(a, "%d", 132);
Run Code Online (Sandbox Code Playgroud)

我会打破这里发生的事情.

  1. 在第一行,我们想确定我们需要多少个字符.前两个参数snprintf告诉它我要写结果的0个字符NULL.当我们这样做时,snprintf实际上不会在任何地方写任何字符,它只会返回已经写入的字符数.这就是我们想要的.
  2. 在第二行,我们动态地将内存分配给char指针.确保并将1添加到所需大小(对于尾随\0终止字符).
  3. 现在有足够的内存分配给char指针,我们可以安全地使用sprintf整数写入char指针.

当然,如果你愿意,你可以使它更简洁.

char * a = malloc(snprintf(NULL, 0, "%d", 132) + 1);
sprintf(a, "%d", 132);
Run Code Online (Sandbox Code Playgroud)

除非这是一个"快速而肮脏"的程序,否则你总是希望释放你所调用的内存malloc.这是C动态方法变得复杂的地方.但是,恕我直言,如果你不想char在大多数情况下只使用其中很小一部分时分配大量指针,那么我不认为这是不好的方法.

  • "alloca"的便携性如何?它肯定不是ANSI C. (5认同)
  • 当然,alloca的便携式C99替代品只是使用可变长度数组?`int size = ...; char a [size + 1]; sprintf的(...`? (3认同)
  • 不要忘记处理 malloc() 返回 NULL 的情况,除非您不关心程序是否崩溃或不安全。如果大小取决于程序外部的输入,则尤其如此。 (2认同)

Reg*_*lez 14

通过使用C++ 11/C99中的vsnprintf,可以使Daniel Standage的解决方案适用于任意数量的参数.

int bufferSize(const char* format, ...) {
    va_list args;
    va_start(args, format);
    int result = vsnprintf(NULL, 0, format, args);
    va_end(args);
    return result + 1; // safe byte for \0
}
Run Code Online (Sandbox Code Playgroud)

c99标准中第7.19.6.12节所述:

vsnprintf函数返回已经写入的字符数已足够大,不计算终止空字符,如果发生
编码错误则返回负值.

  • _vscprintf只是微软. (4认同)
  • `_vscprintf` 是更好的解决方案。看看 - /sf/answers/655846971/ (2认同)

Ste*_*sop 13

在一个int位的最大可能数量是CHAR_BIT * sizeof(int),和一个十进制数是"价值"至少3个比特,等等对于任意所需要的空间的松散上限int(CHAR_BIT * sizeof(int) / 3) + 3.+3是因为我们在划分时向下舍入,一个用于符号,一个用于nul终止符.

如果通过"在32位系统上"表示您知道int是32位,那么您需要12个字节.10为数字,1为符号,1为nul终结符.

在您要转换的int的特定情况下132,您需要4个字节.Badum,tish.

在固定大小的缓冲区可以使用合理范围的情况下,它们是更简单的选项.我不是那么谦卑地提出上面的限制是合理的(对于32位int,13个字节而不是12个,而对于64位,则为23个字节而不是21个int).但对于困难的情况,在C99你可以打电话snprintf来获得大小,然后malloc那么多.对于这样一个简单的案例来说,这太过分了.

  • 这很危险 - 一个典型的潜在缓冲区溢出情况.`printf`系列函数的确切输出取决于语言环境.例如,区域设置可以设置"千位"分隔符. (6认同)
  • @Eric:这个问题是关于C的,与`std :: string`无关. (4认同)
  • 使用`malloc`这是荒谬的.它通过添加您必须检查的故障案例来使代码过度复杂化 - 如果失败,您会怎么做?!?只需使用正确大小的缓冲区,就像您解释的那样. (2认同)
  • @R:如果编写代码的人有兴趣学习或了解语言本身的基础,那么使用malloc并不荒谬.告诉人们只使用std :: string,因为所有艰苦的工作已经做到了这一点是无知的; 也就是说想知道事情在引擎盖下是如何运作的.也许原始海报想知道std :: string是如何做的呢? (2认同)
  • @Brett:你让我在那里呆了一分钟,但是`%d`当然不使用千位分隔符。“%d”会,但这不是问题。 (2认同)

小智 8

我看到这个对话已经有几年了,但我在尝试找到MS VC++的答案时找到了它,其中snprintf不能用于查找大小.我会发布我最终找到的答案,以防它帮助其他人:

VC++具有_scprintf专门用于查找所需字符数的功能.