【问题标题】:size limit of printf conversion specificationprintf 转换规范的大小限制
【发布时间】:2011-04-28 00:42:26
【问题描述】:

printf 转换规范是% 后跟标志、宽度、精度、长度修饰符和转换说明符。转换规范的大小是否有实际限制?

%s 是 2 个字符长,而 %08.2f 是 6 个字符长。我的问题是,根据 C99 标准,可以创建的格式字符串中的最大单个规范的长度是多少?

【问题讨论】:

  • 我很好奇——除了好奇,你还有什么想知道的吗?
  • @nategoose:我正在考虑围绕snprintf 使用一个非常特殊的包装器,并想了解我是否可以静态分配一些临时缓冲区
  • 看看 GNU 的 libc 实现怎么样?如果你允许尽可能多,你应该足够好。
  • 我认为我曾经看过的一个足够简单易读的实现只是解释了转换规范——使用带有几个整数变量的状态机,直到它到达类型。然后数据类型处理代码使用这些整数和输出参数(当然是处理默认状态),因此在整数字符串之外没有任何限制,因为它们太大而无法放入整数。我认为这是 Nut/OS 实现

标签: c printf c99 format-string


【解决方案1】:

没有这种最大长度的转换规范。如果你认为你找到了这样的规范,我可以想出一个长 1 个字符的规范。

例如,考虑字段宽度和精度。该标准说它们是十进制整数,但没有指定它们的范围。因此,您可以编写具有任意大整数作为字段宽度或精度的转换说明符。

【讨论】:

  • 这就是为什么问“实用”这个问题,毕竟这个宽度是有限的,大值是无效的。即使是 64 位,它实际上也是有限的
  • 虽然printf 可能不会(也不需要)强制执行任何限制,但printf 返回打印的字符数这一事实意味着您将得到未指定/未定义(不清楚哪个) 行为,如果您使用非常大的字段宽度/精度。格式说明符可能是无限长度的一个更现实的原因是冗余标志,例如%+++++++++++++++++++++++d.
  • @zaharpopov:嗯,问题中有两种方法1)实用2)根据标准。我采取了后一种方法。前者取决于编译器和库的实现。
【解决方案2】:

如果你的意思是一个文字字符串,它是 4095 个字符

5.2.4.1 翻译限制
...
-- 字符串文字或宽字符串文字中的 4095 个字符(连接后)
...

我被 C89 509 个字符的限制所困扰(不适用于 printf/scanf 格式字符串),所以这是 C99 带来的良好变化之一 :-)


编辑:glibc 实现(非标准定义

glibc 实现从 read_int 函数获取宽度。
所以,对于这个实现,显然,也许,限制是 INT_MAX(我还没有搜索过 read_int 函数)。

【讨论】:

  • 是的,但这不是我的问题。格式可能不是文字 - 我的问题是关于 % 之后的最大说明符的长度
【解决方案3】:

printf 转换规范是 % 后跟标志、宽度、精度、长度修饰符和转换说明符。转换规范的大小是否有实际限制?

过去我不得不处理几个标准的printf 实现,我的总体印象是没有施加特别的限制。

格式字符串一般是逐字符解析的。 (想想简单的FSM。)大多数printf 实现避免在内部缓冲任何内容,即使对于数字,也使用逐字符转换为十进制(甚至不是atoi)。

例如,您可以检查printf 是如何在FreeBSD kernel 内部实现的(许多其他实现通常会从其中提取代码)。这肯定是简化的实现(通过几个内核特定的调整),但它反映了通常如何处理格式字符串。

注意刚刚检查了 glibc 的 vfprintf() 实现,它们在内部分配了一个带有 malloc() 的缓冲区(如果需要)。所以没有特别的限制。

我的问题是,根据 C99 标准,可以创建的格式字符串中的最大单个规范的长度是多少?

格式说明符是字符串的一部分,据我所知,字符串长度不受标准限制。正如我上面提到的,我从未见过有任何此类限制的实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    • 2020-06-21
    相关资源
    最近更新 更多