【问题标题】:What is the behavior when a printf specifier flag is repeated?重复 printf 说明符标志时的行为是什么?
【发布时间】:2026-01-20 01:00:01
【问题描述】:

fprintf() 系列函数有 5 个 标志 个字符 '-''+'' ''#''0'

当一个标志重复时,指定的行为是什么?

#include <stdio.h>
int main(void) {
  printf("%  d\n", 12);     //  12
  printf("%00d\n", 34);     // 34
  printf("%++d\n", 56);     // +56
  printf("%00*d\n", 5, 78); // 00078
  return 0;
}

使用我的 gcc“i686-pc-cygwin/4.9.2”,我收到“警告:格式为 [-Wformat=] 的重复 ' ' 标志”,所以我认为这是一个正确的行为 --> 警告用户并允许重复的标志。

我还没有找到 C99/C11 规范指南来解决在尝试编写格式解析器时发现的这个角落问题。

如果允许重复,下面的代码是可以的。如果不允许重复,则第二个0 是宽度。那么说明符有2个宽度0*,这又是一个问题。

// -------v
printf("%00*d\n", 5, 78); // 00078

【问题讨论】:

  • FWIW,我在 VS 2008 和 VS 2010 上得到了相同的结果。
  • 当然不需要警告,即使是格式不正确的字符串。格式字符串可以在运行时构造;在一般情况下,编译器无法判断它是否正确。一些编译器,例如 gcc,会在格式字符串是文字时警告不正确的格式字符串(最常见的情况)。 (这并不能回答您关于是否允许重复标志的问题。)
  • 我见过printf 的一些实现,并且我已经写了至少4 个不同的。它们都将重复的标志处理为等同于单个标志,原因很简单,这样做要简单得多,而且对于少数对此感到疑惑的实现者来说,这似乎并没有错。
  • @chqrlie 同意将重复标志处理为等同于单个标志更简单。

标签: c printf language-lawyer


【解决方案1】:

在我看来,这一点上的标准并不清楚。

gcc 的作者清楚地认为重复标志是无效的,因为 gcc 默认会针对以下内容发出警告:

printf("%++d\n", 42);

但这并不一定能告诉我们标准作者的意图。

标准允许:

零个或多个标志(以任何顺序)修改转换的含义 规范。

标志是-+空格#0。我认为,“零个或多个标志*”这个短语专门用于允许组合不同的标志。例如,这个:

#include <stdio.h>
int main(void) {
    printf("|%6x|\n", 0x123);
    printf("|%-6x|\n", 0x123);
    printf("|%#6x|\n", 0x123);
    printf("|%-#6x|\n", 0x123);
    printf("|%#-6x|\n", 0x123);
}

是有效的并产生这个输出:

|   123|
|123   |
| 0x123|
|0x123 |
|0x123 |

在其他情况下,该标准明确规定了一个结构是否可以重复。例如,long long intlong int 不同,long int int 是语法错误。另一方面,标准明确指出 (N1570 6.7.3p5):

如果同一个限定符在同一个文件中出现多次 specifier-qualifier-list,直接或通过一个或多个 typedefs,行为与只出现一次相同。

这里没有任何这样的声明让我怀疑标准的作者没有考虑重复相同标志的情况。

如果我对此不正确,并且委员会确实打算将重复标志等同于单个标志,那么您的格式解析器应该将它们视为等效。如果我是正确的,那么重复相同标志的行为是未定义的,您的实现可以做任何您喜欢的事情 - 包括将它们视为等同于单个标志。

无论哪种情况,您都可以随意发出警告。即使标准定义了重复标志的行为,它仍然可以说是糟糕的风格,值得警告。

【讨论】:

  • @ShafikYaghmour printf("%d", 10.1); 也不会导致 gcc 发出警告之外的任何内容,即使是 -pedantic-errors
  • @T.C.:就标准而言,printf("%d", 10.1) 只是具有未定义的行为。一个实现可以诊断它,甚至拒绝它,但它不是要求做任何特别的事情。如果它在if (0) printf("%d", 10.0); 这样的上下文中,它不应被拒绝。
  • 我知道。我的评论是对 Shafik 的(自删除后)评论的回应,即 gcc 没有将重复标志警告升级为带有-pedantic-errors 的错误,表明它认为它符合要求。
  • @T.C.事实上,我最初的想法是 Wformat 产生的警告并不都是由于无效程序造成的,但我意识到无论如何你都需要 Werror 将它们变成错误。
【解决方案2】:

在 C 标准(7.21.6.1 的 fprintf 函数)中只写了

4 每个转换规范都由字符 % 引入。 在 % 之后,依次出现以下内容:

零个或多个标志(以任何顺序),用于修改 转换规范。

所以我想标志可能会重复。否则会有一些限制。

【讨论】:

    【解决方案3】:

    标准说:

    7.19.6.1/4 零个或多个标志(以任何顺序)修改转换规范的含义。

    “零个或多个标志”显然是为了允许指定多个标志。有意义的是,如果一个标志重复出现,它与只出现一次的标志具有相同的含义。

    【讨论】: