为什么 snprintf() 采用 size_t 大小限制,但 returns 打印的字符数为 int?

Why does snprintf() take a size_t size limit, but returns an int number of chars printed?

令人尊敬的 snprintf() 函数...

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

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

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

如果它不能打印超过 INT_MAX 个字符,为什么 bufszsize_t 而不是 unsignedint?或者 - 它是否至少被正式限制为不大于 INT_MAX 的值?

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

这也是为什么 printf 参数列表中读取的参数 * 宽度或格式精度是 int 而不是 [=11= 的原因].

snprintf 较新,因此它作为参数的大小被定义为 size_t,但 return 值保留为 int使其与 printfsprintf.

相同

请注意,您可以使用这些函数打印多于 INT_MAX 个字符,但如果这样做,return 值是未指定的。在大多数平台上,intsize_t 都将以相同的方式被 return 编辑(在主 return 值寄存器中),只是 size_t 值可能超出 int 的范围。如此多的平台实际上来自所有这些例程 return a size_t(或 ssize_t),并且超出范围的事情通常会正常工作,即使标准不要求它。

If snprintf() is supposed to be able to print more than INT_MAX characters into the buffer, surely it must return an ssize_t or a size_t with (size_t) - 1 indicating an error, right?

不完全是。

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

The number of characters that can be produced by any single conversion shall be at least 4095." C17dr § 7.21.6.1 15

每个 % 超过 4095 的任何东西都会冒可移植性的风险,因此 int,即使是 16 位 (INT_MAX = 32767),也足以满足大多数可移植代码的目的。

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

How does it make sense for the buffer size to be size_t, but for the return type to be only an int?

The official C99 rationale document 没有讨论这些特定的考虑因素,但大概是出于一致性和(单独的)意识形态原因:

  • 所有 printf 家族功能 return 和 int 具有基本相同的意义。这是在发明 size_t 之前就定义的(对于原始的 printffprintfsprintf)。

  • type size_t 在某种意义上是传达大小和长度的正确类型,因此它被用于 snprintfvsnprintf 的第二个参数这些是在 C99 中引入的(连同 size_t 本身)。

If snprintf() is supposed to be able to print more than INT_MAX characters into the buffer, surely it must return an ssize_t or a size_t with (size_t) - 1 indicating an error, right?

那将是一个内部更一致的设计选择,但不是。似乎已经选择了跨函数系列的一致性。请注意,此系列中的 none 函数已记录了它们可以输出的字符数限制,并且它们的一般规范暗示没有内在限制。因此,他们都遇到了输出很长的相同问题。

And if it is not supposed to be able to print more than INT_MAX characters, why is bufsz a size_t rather than, say, an unsigned or an int? Or - is it at least officially constrained to hold values no larger than INT_MAX?

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

所以是的,当通过这些函数输出非常大的数据时,实现将难以根据规范运行,其中“非常大”是依赖于实现的。那么,作为一个实际问题,不应依赖于使用它们在单个调用中发出非常大的输出(除非有人打算忽略 return 值)。

大小和 return 之间的差异已在线程 https://www.austingroupbugs.net/view.php?id=761 的标准组中讨论。这是该线程末尾发布的结论:

Further research has shown that the behavior when the return value would overflow int was clarified by WG14 in C99 by adding it into the list of undefined behaviors in Annex J. It was updated in C11 to the following text:

"J.2 Undefined behavior The behavior is undefined in the following circumstances: [skip] — The number of characters or wide characters transmitted by a formatted output function (or written to an array, or that would have been written to an array) is greater than INT_MAX (7.21.6.1, 7.29.2.1)."

请注意,此说明提及 snprintf 的大小参数或缓冲区的大小。