Как позиционные аргументы, такие как «1 $», работают с printf ()? - PullRequest
14 голосов
/ 12 июня 2011

По man Я нахожу

               printf("%*d", width, num);

и

               printf("%2$*1$d", width, num);

эквивалентны.

Но ИМО второй стиль должен быть таким же, как:

               printf("%*d", num, width);

Однако при тестировании кажется, что man прав; почему?

Ответы [ 4 ]

24 голосов
/ 12 июня 2011

Соответствующая часть спецификации POSIX printf() определяет это поведение:

Преобразования могут применяться к n -ому аргументу после формата в списке аргументов, а не к следующему неиспользованному аргументу. В этом случае символ спецификатора преобразования% (см. Ниже) заменяется последовательностью "% n $", где n - это десятичное целое число в диапазоне [1, {NL_ARGMAX}], задающее позицию аргумента в списке аргументов. Эта функция обеспечивает определение строк формата, которые выбирают аргументы в порядке, соответствующем конкретным языкам (см. Раздел ПРИМЕРЫ).

Формат может содержать либо нумерованные спецификации преобразования аргументов (то есть "% n $" и "* m $"), либо ненумерованные спецификации преобразования аргументов (то есть% и *), но не оба. Единственным исключением является то, что %% можно смешивать с формой «% n $». Результаты смешивания нумерованных и ненумерованных спецификаций аргументов в строке формата не определены. Когда используются спецификации нумерованных аргументов, для указания N -ого аргумента необходимо, чтобы все ведущие аргументы, от первого до ( N-1 ) -го, были указаны в строке формата.

В строках формата, содержащих форму преобразования "% n $", нумерованные аргументы в списке аргументов могут ссылаться из строки формата столько раз, сколько требуется.

%n$ определяет аргумент, значение которого должно быть напечатано - аргумент 2 в вашем примере.

*n$ определяет аргумент, значение которого следует рассматривать как ширину формата - аргумент 1 в вашем примере.

Итак, те, кто писал руководство, следовали стандарту.


Вы утверждаете в комментарии:

2$* должен соответствовать второму параметру, в то время как 1$d должен соответствовать первому, но оказывается, что в случае printf("%2$*1$d", width, num);.

это не так.

Как уже отмечалось, стандарт явно прикрепляет части n$ в качестве постфиксных модификаторов % и *, а не в качестве префиксных модификаторов спецификатора преобразования формата (d в этом примере) и * , Ваш предполагаемый дизайн, возможно, можно заставить работать, но он не был выбран.

3 голосов
/ 12 июня 2011

Во втором примере:

printf("%2$*1$d", width, num);

Первое число 2 прикреплено к описателю формата, а второе число 1 прикреплено к *. Если вы прочитали документацию для printf, это ясно. Ничего необычного не происходит.

1 голос
/ 12 июня 2011

Звездочкой может быть обозначена ширина или точность поля, или и то, и другое. '*' или звездочка, за которой следуют одна или несколько десятичных цифр и `$ ' вместо строки цифр.

Таким образом, 1$ относится к звездочке, поэтому первый аргумент - это ширина. 2$ применяется ко всей спецификации формата, поэтому вторым аргументом является тот, значение которого будет напечатано.

0 голосов
/ 10 января 2019

Я согласен, что справочная страница сбивает с толку, поскольку она объясняет два понятия ( модификатор длины как позиционный аргумент ) в примере one и я иду к могучей паре vi / gcc:

test.c

#include <stdio.h> 
void main(int argc, char** argv) {
    printf("%1$c\n", 'a', 'b', 'c');
    printf("%2$c\n", 'a', 'b', 'c');
    printf("%3$c\n", 'a', 'b', 'c');
    printf("%3$c %2$c %1$c\n", 'a', 'b', 'c');
}

Компиляция выдаст предупреждения, если используются не все аргументы:

$ gcc test.c
test.c: In function ‘main’:
test.c:3:9: warning: unused arguments in $-style format [-Wformat-extra-args]
  printf("%1$d\n", 'a', 'b', 'c');
         ^~~~~~~~
test.c:4:9: warning: format argument 1 unused before used argument 2 in $-style format [-Wformat=]
  printf("%2$d\n", 'a', 'b', 'c');
         ^~~~~~~~
test.c:4:9: warning: unused arguments in $-style format [-Wformat-extra-args]
test.c:5:9: warning: format argument 1 unused before used argument 3 in $-style format [-Wformat=]
  printf("%3$d\n", 'a', 'b', 'c');
         ^~~~~~~~
test.c:5:9: warning: format argument 2 unused before used argument 3 in $-style format [-Wformat=]

Но тут вы видите результат:

$ ./a.out
a
b
c
c b a
...