`printf("%. - 1s \n","foo")`是否调用未定义的行为?

vmo*_*eco 7 c standards printf undefined-behavior language-lawyer

根据标准:

每个转换规范由字符%引入.在%之后,以下顺序出现:

  • 零个或多个标志[...].
  • 可选的最小字段宽度.[...]
  • 一个可选的精度,它提供了为s转换写入的最大字节数.精度采用句点(.)后跟[...]可选十进制整数的形式;
  • 可选的长度修改器[...].+转换说明符[...].
  • 可选的最小字段宽度.[...]
  • 转换说明符[...].

后来:

如果省略精度,则采用负精度参数.

printf("%.-1s\n", "foo")根据我如何解释标准定义,我期望得到什么:

我从标准中得到的第二个引用表明我们可以传递一个负精度参数,并且这种精度会被忽略.

所以,printf("%.-1s\n", "foo")应该相当于printf("%s\n", "foo"),它会显示"foo\n"和返回4.

然而,这是printf("%.-1s\n", "foo")我使用的系统(osx)上的实际行为:

printf("%.-1s\n", "foo")显示" \n"和返回2.

这显然不同于我的预期.

  • 不知怎的,我对标准的解释错了吗?
  • 这种行为是不确定的?
  • 传递负精度(编辑:没有星号)实际上可能吗?

Joh*_*ger 1

  • 我对标准的解释是否有误?

我认为你的解释可以总结如下:

因此,printf("%.-1s\n", "foo")应该相当于printf("%s\n", "foo"),它将显示"foo\n"并返回 4。

不。您引用的有关忽略负精度参数的规定不适用于这种情况。该条款讨论的是在格式字符串中指定精度*并将该值作为单独printf参数传递的选项:

printf("%.*s\n", -1, "foo");
Run Code Online (Sandbox Code Playgroud)

在这种情况下,负精度参数会导致printf()其行为就像未指定精度一样。你的情况有所不同。

另一方面,这里的标准并不要求格式字符串中出现的精度值是非十进制整数。它确实在其他几个地方以这种方式限定术语“十进制整数”,包括同一部分前面的内容,但在有关精度字段的段落中却没有这样做。

  • 这种行为是未定义的吗?

不。对所需语义有两种相互冲突的解释(见下文),但无论哪种方式,标准都定义了行为。它可以解释为

  • 当负精度值直接在格式字符串中呈现时,针对负精度参数描述的行为也适用。这样做的优点是一致性,并且这是您报告观察到的行为。然而,

  • 标准的字面解读表明,当精度在格式字符串中表示为负十进制整数时,则应用该部分中描述的普通语义;对于s指令,负精度表示要输出的最大字符数。

您观察到的行为与前一种解释不一致,但考虑到输出少于 0 字节的实际困难,后一种解释未成功实现对我来说并不奇怪。我倾向于猜测后者是您的实现试图实现的。

我怀疑这是在某个阶段的无意遗漏,为精度字段提供了负值的可能性,但无论有意与否,标准似乎都允许这样做。