简体   繁体   English

像“1$”这样的位置 arguments 如何与 printf() 一起工作?

[英]How do positional arguments like “1$” work with printf()?

By man I find我找到man

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

and

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

are equivalent.是等价的。

But IMO the second style should be the same as:但 IMO 的第二种风格应该与以下相同:

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

However via testing it seems man is right;然而,通过测试,似乎man是对的; why?为什么?

The relevant part of the POSIX specification of printf() defines this behaviour: printf()的 POSIX 规范的相关部分定义了这种行为:

Conversions can be applied to the n th argument after the format in the argument list, rather than to the next unused argument.转换可以应用于参数列表中格式之后的第n个参数,而不是下一个未使用的参数。 In this case, the conversion specifier character % (see below) is replaced by the sequence "%n$", where n is a decimal integer in the range [1,{NL_ARGMAX}], giving the position of the argument in the argument list.在这种情况下,转换说明符字符 %(见下文)被序列“%n$”替换,其中n是 [1,{NL_ARGMAX}] 范围内的十进制 integer,给出参数中参数的 position列表。 This feature provides for the definition of format strings that select arguments in an order appropriate to specific languages (see the EXAMPLES section).此功能提供了格式字符串的定义,即 select arguments 以适合特定语言的顺序(参见示例部分)。

The format can contain either numbered argument conversion specifications (that is, "%n$" and "*m$"), or unnumbered argument conversion specifications (that is, % and * ), but not both.格式可以包含编号的参数转换规范(即“%n$”和“*m$”)或未编号的参数转换规范(即 % 和 * ),但不能同时包含两者。 The only exception to this is that %% can be mixed with the "%n$" form.唯一的例外是 %% 可以与 "%n$" 形式混合使用。 The results of mixing numbered and unnumbered argument specifications in a format string are undefined.在格式字符串中混合编号和未编号的参数规范的结果是未定义的。 When numbered argument specifications are used, specifying the N th argument requires that all the leading arguments, from the first to the ( N-1 )th, are specified in the format string.当使用编号参数规范时,指定第N个参数需要在格式字符串中指定所有前导 arguments,从第一个到第 ( N-1 ) 个。

In format strings containing the "%n$" form of conversion specification, numbered arguments in the argument list can be referenced from the format string as many times as required.在包含转换规范“%n$”形式的格式字符串中,参数列表中编号为 arguments 的格式字符串可以根据需要多次引用。

The %n$ identifies the argument whose value is to be printed - argument 2 in your example. %n$标识要打印其值的参数 - 在您的示例中为参数 2。

The *n$ identifies the argument whose value is to be treated as the format width - argument 1 in your example. *n$标识其值将被视为格式宽度的参数 - 在您的示例中为参数 1。

So, those writing the manual followed the standard.因此,编写手册的人遵循了标准。


You argue in a comment:你在评论中争论:

2$* should match the 2nd parameter while 1$d should match the first one, but it turns out that it's not true in the case of printf("%2$*1$d", width, num); 2$*应该匹配第二个参数,而1$d应该匹配第一个参数,但事实证明在printf("%2$*1$d", width, num); . .

As noted already, the standard clearly attaches the n$ parts as postfix modifiers of % and * , rather than as prefix modifiers of the format conversion specifier ( d in this example) and * .如前所述,该标准清楚地将n$部分附加为%*的后缀修饰符,而不是格式转换说明符(本例中为d )和*的前缀修饰符。 Your putative design could, probably, be made to work, but was not the design chosen.您推定的设计可能会起作用,但不是选择的设计。

In your second example:在您的第二个示例中:

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

The first number, 2, is attached to the format specifier, and the second number, 1, is attached to the * .第一个数字 2 附加到格式说明符,第二个数字 1 附加到* If you read the documentation for printf , this is clear.如果您阅读printf的文档,这很清楚。 Nothing unusual is happening.没有什么不寻常的事情发生。

A field width or precision, or both, may be indicated by an asterisk '*' or an asterisk followed by one or more decimal digits and a `$' instead of a digit string.字段宽度或精度或两者都可以用星号“*”或星号后跟一个或多个十进制数字和“$”来表示,而不是数字字符串。

So the 1$ applies to the asterisk, therefore the first argument is the width.所以1$适用于星号,因此第一个参数是宽度。 The 2$ applies to the entire format specification, therefore the second argument is the one whose value will be printed. 2$适用于整个格式规范,因此第二个参数是将打印其值的参数。

I agree that the man page is confusing because it explains two concepts ( length modifier as positional argument ) in one example, so I go to the mighty couple vi / gcc :我同意手册页令人困惑,因为它在一个示例中解释了两个概念(长度修饰符作为位置参数),所以我 go 对强大的一对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');
}

Compiling will give warnings if not all arguments are used:如果未使用所有 arguments,编译将给出警告:

$ 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=]

But then here you see the result:但是在这里你会看到结果:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM