Каково поведение, когда флаг спецификатора printf повторяется?

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 для этой угловой проблемы, обнаруженной при попытке написать парсер формата.

Если повторение разрешено, следующий код в порядке. Если повторение не разрешено, 2-й 0 является шириной. Тогда спецификатор имеет 2 ширины 0 и *, что является еще одной проблемой.

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

Ответ 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 int отличается от long int, а long int int является синтаксической ошибкой. С другой стороны, стандарт явно говорит (N1570 6.7.3p5), что:

Если один и тот же определитель появляется более одного раза в одном и том же спецификатор-классификатор-список, либо напрямую, либо через один или несколько typedefs, поведение такое же, как если бы оно появилось только один раз.

Отсутствие такого заявления здесь заставляет меня подозревать, что авторы стандарта не рассматривали случай повторения одного и того же флага.

Если я ошибаюсь в этом вопросе, и комитет решил, что повторяющийся флаг будет эквивалентен одному флагу, тогда ваш синтаксический анализатор формата должен рассматривать их как эквивалентные. Если я прав, то поведение повторения одного и того же флага будет undefined, и ваша реализация может делать все, что вам нравится, включая обращение к ним как эквиваленту одного флага.

В любом случае вы можете отправить предупреждение, если хотите. Даже если стандарт определяет поведение повторяющегося флага, он все еще может быть плохого стиля и заслуживает внимания.

Ответ 2

В стандарте C (7.21.6.1 функция fprintf) записано только то, что

4 Каждая спецификация преобразования вводится символом%. После% появляются следующие последовательности:

- Нулевые или более флагов (в любом порядке), которые изменяют значение изменение спецификация.

Итак, я полагаю, что флаги могут повторяться. В противном случае были бы некоторые ограничения.

Ответ 3

В стандарте говорится:

7.19.6.1/4 Ноль или более флагов (в любом порядке), которые изменяют значение спецификации преобразования.

"нуль или больше флагов", очевидно, предназначено для указания более одного флага. Имеет смысл, что если флаг повторяется, он имеет то же значение, что и флаг, который появляется только один раз.