How do positional arguments like "1$" work with printf()?

The relevant part of the POSIX specification of printf() defines this behaviour:

Conversions can be applied to the nth argument after the format in the argument list, rather than to the next unused argument. 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. This feature provides for the definition of format strings that select arguments in an order appropriate to specific languages (see the EXAMPLES section).

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. The only exception to this is that %% can be mixed with the "%n$" form. The results of mixing numbered and unnumbered argument specifications in a format string are undefined. When numbered argument specifications are used, specifying the Nth argument requires that all the leading arguments, from the first to the (N-1)th, are specified in the format string.

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.

The %n$ identifies the argument whose value is to be printed - argument 2 in your example.

The *n$ identifies the argument whose value is to be treated as the format width - argument 1 in your example.

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);.

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 *. 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 *. If you read the documentation for printf, this is clear. Nothing unusual is happening.

Tags:

C

Printf

Format