printf - Reordering Arguments using $

Ju Hong Kim · February 28, 2021

Report a bug

I was recently watching a video by Live Overflow helping a person troubleshoot a format string exploit through Twitter, and saw something I was very curious about. In the video, the Yotuber poses a question to the person if they could describe how %2$s prints a string. I have never seen this syntax before. What does the dollar sign ($) serve in the format string? This got me curious so I went searching on the internet and the man pages to find out.

Turns out $ is from the POSIX extension and does not appear in C99. Its purpose is to display parameters (argument) in different orders. By default, printf displays the argument in the order you specify them. For instance, if we look at the code below, printf will display Feb 28 2021

printf("%s %d %d\n", month, day, year);

However, what if we want to change the order of the date to be year month day instead. One way is to reorder the arguments. This can get very tedious when you have a lot of parameters to reorder so that’s where the dollar sign ($) comes to play:

printf("%3$d %1$s %2$d\n", month, day, year);

The code above achieves the same result as the code below, outputting 2021 Feb 28.

printf("%d %s %d\n", year, month, day);                                    

How $ format works

From the man page and experimenting around, here’s the follow what I learned:

  • Format %m$ where m is the index of the argument list starting from 1
    • i.e. %3$d to denote the 3rd argument in the list
  • Once the order is explicitly stated using $ style, the order of all conversions in the format string must be included explicitly. Failure to do so will result in a warning if compiled with -Wall option
  • Gaps cannot exist: All arguments must appear once in the format string. For instance, if arguments 1 & 3 are used, argument 2 must also be used in the string to not raise a warning

Conclusion

The $ style in printf allows programmers to change the order of the arguments easily through the format string. This saves a lot of time and headache of manually reordering all the arguments in printf. Another benefit is to simplify or select what element you wish to see on the stack. For instance, if you want to see the 13th element in the stack, you could simply write %13$x instead of repeating %x 13 times.

Twitter, Facebook