3

尊贵的snprintf()功能...

int snprintf( char *restrict buffer, size_t bufsz, const char *restrict format, ... );

它:

  • 返回它打印的字符数,或者更确切地说,如果没有缓冲区大小限制,它会打印的数字。
  • 以字符/字节为单位获取缓冲区的大小。

缓冲区大小如何有意义size_t,但返回类型只是一个int

如果snprintf()应该能够将多个INT_MAX字符打印到缓冲区中,那么它肯定必须返回一个ssize_t或一个size_t(size_t) - 1指示错误,对吧?

如果它不应该打印多个INT_MAX字符,为什么是bufszasize_t而不是,比如说, anunsigned或 an int?或者 - 至少官方限制持有不大于 的值INT_MAX

4

3 回答 3

3

printf早于size_t和类似的“便携式”类型的存在——当printf第一次标准化时, a 的结果sizeof是一个int.

这也是为什么在格式printf中读取的*宽度或精度的参数列表中的参数是 anint而不是 a 的原因size_t

snprintf是较新的,因此将其作为参数的大小定义为 a size_t,但返回值保留为 anint以使其与printfand相同sprintf

请注意,您可以使用这些函数打印多个INT_MAX字符,但如果这样做,则返回值未指定。在大多数平台上, anint和 asize_t都将以相同的方式返回(在主返回值寄存器中),只是一个size_t值可能超出了 an 的范围int。如此多的平台实际上从所有这些例程中返回一个size_t(或ssize_t)并且超出范围的事情通常会正常工作,即使标准不需要它。

于 2022-01-05T21:14:13.593 回答
1

如果snprintf()应该能够将多个INT_MAX字符打印到缓冲区中,那么它肯定必须返回一个ssize_t或一个size_t(size_t) - 1指示错误,对吧?

不完全的。

C对和朋友也有一个环境限制。fprintf()

任何一次转换可以产生的字符数至少应为 4095。” C17dr § 7.21.6.1 15

每个超过 4095 的任何东西都%存在可移植性风险,因此int,即使是 16 位 ( INT_MAX = 32767),对于可移植代码的大多数用途来说也足够了。

注意:这ssize_t不是 C 规范的一部分。

于 2022-01-05T21:35:17.630 回答
1

缓冲区大小为size_t,但返回类型仅为 int 有何意义?

官方的 C99 基本原理文档没有讨论这些特殊考虑,但可能是出于一致性和(单独的)意识形态原因:

  • 所有printf-family 函数都返回int具有基本相同意义的 an。这在发明之前就已经定义了(对于原始printffprintf, 和sprintf) 。size_t

  • typesize_t在某种意义上是传达尺寸和长度的正确类型,因此它被用于第二个参数snprintf以及何时在 C99vsnprintf中引入这些参数(连同其自身)。size_t

如果snprintf()应该能够将多个INT_MAX字符打印到缓冲区中,那么它肯定必须返回一个ssize_t或一个size_t(size_t) - 1指示错误,对吧?

那将是一个更加内部一致的设计选择,但不是。似乎选择了跨函数族的一致性。请注意,该系列中的任何函数都没有记录对它们可以输出的字符数的限制,并且它们的一般规范意味着没有固有的限制。因此,它们都面临同样的问题,即输出很长。

如果它不应该打印多个INT_MAX字符,为什么是 bufsz asize_t而不是 anunsigned或 an int?或者 - 至少官方限制持有不大于 的值INT_MAX

对于第二个参数的值没有记录的约束,除了它必须可以表示为的隐含约束size_t。甚至在最新版本的标准中也没有。但请注意,也没有任何内容表明 typeint不能表示所有可表示的值size_t(尽管在大多数实现中确实不能)。

所以是的,当通过这些函数输出非常大的数据时,实现将无法按照规范执行,其中“非常大”取决于实现。因此,实际上,不应依赖使用它们在一次调用中发出非常大的输出(除非打算忽略返回值)。

于 2022-01-05T21:44:22.697 回答