# How fmtlib Implements the POSIX Positional printf Extension

> Discover how fmtlib implements POSIX positional printf extensions. Learn about its parsing system for reordered arguments and positional width precision specifiers.

- Repository: [Hello World Foundation/fmt](https://github.com/fmtlib/fmt)
- Tags: internals
- Published: 2026-09-04

---

**fmtlib implements the POSIX positional printf extension in [`include/fmt/printf.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/printf.h) through a coordinated parsing system where `parse_header` extracts explicit argument indices and a `get_arg` lambda resolves them against the argument list, enabling both reordered arguments and positional width/precision specifiers.**

The {fmt} library (fmtlib/fmt) provides a modern C++ formatting API that includes comprehensive support for POSIX positional printf syntax. This extension allows format strings to reference arguments by explicit position (e.g., `%2$d %1$s`) and to specify widths or precisions via separate argument indices (e.g., `%*3$d`). The implementation centers on two tightly-coupled components within [`include/fmt/printf.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/printf.h) that handle parsing and argument resolution.

## Core Parsing Components

The implementation relies on two primary mechanisms defined in [`include/fmt/printf.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/printf.h):

- **parse_header** (lines 330-381): Parses optional argument indices (`%2$d`), width specifications (`%*3$d`), and precision modifiers (`%.*4$f`). It detects the trailing `$` character that denotes a positional index and returns the resolved argument index to the formatter.

- **get_arg lambda** (lines 13-23): Retrieves arguments either by the next sequential index or by an explicit index supplied by `parse_header`. It validates indices against the parsing context to prevent out-of-bounds access.

## Parsing Argument Indices

When the parser encounters a digit (`0`-`9`) immediately following a `%` character, it invokes `parse_nonnegative_int`. If the next character after the number is `$`, the numeric value is interpreted as an explicit argument index rather than a width or precision value.

```cpp
if (it != end && *it == '$') {          // value is an argument index
    ++it;
    arg_index = value != -1 ? value : max_value<int>();
}

```

The computed `arg_index` is passed to the `get_arg` lambda, which adjusts the value by decreasing it by one to account for zero-based internal identifiers. This enables syntax like `%2$d` to correctly reference the second argument in the parameter list.

## Positional Width and Precision

The POSIX extension allows `*` width and `.*` precision specifiers to reference specific arguments using the `*N$` and `.*N$` syntax. Inside `parse_header`, after handling standard width parsing, the code checks for the `*` character followed by a numeric index:

```cpp
else if (*it == '*') {
    ++it;
    // Check for positional width argument like *1$
    if (it != end && *it >= '0' && *it <= '9') {
        int width_index = parse_nonnegative_int(it, end, -1);
        if (it != end && *it == '$') {
            ++it;
            specs.width = static_cast<int>(
                get_arg(width_index).visit(detail::printf_width_handler(specs)));
        } else {
            report_error("invalid format specifier");
        }
    } else {
        specs.width = static_cast<int>(
            get_arg(-1).visit(detail::printf_width_handler(specs)));
    }
}

```

The same pattern appears for precision handling at lines 458-471 in the same file. The `get_arg(width_index)` call retrieves the N-th argument, which `printf_width_handler` or `printf_precision_handler` then processes to obtain the concrete integer value.

## Argument Retrieval Logic

The `vprintf` function creates a `parse_context` that tracks the total argument count and the "next" argument position. The `get_arg` lambda implements the resolution logic:

```cpp
auto get_arg = [&](int arg_index) {
    if (arg_index < 0)
        arg_index = parse_ctx.next_arg_id();          // sequential
    else
        parse_ctx.check_arg_id(--arg_index);          // explicit positional
    auto arg = context.arg(arg_index);
    if (!arg) report_error("argument not found");
    return arg;
};

```

When `arg_index` is negative, the system uses sequential argument ordering. For explicit positive indices, the lambda validates the index and decrements it to convert from the user-facing one-based indexing to the internal zero-based representation used by `basic_printf_context`.

## Integration with the printf Engine

After `parse_header` returns the resolved `arg_index`, the formatter executes a four-stage pipeline:

1. **Precision parsing**: Identical handling of `*N$` syntax for precision specifiers.
2. **Argument conversion**: The selected argument is transformed to the required type via `convert_arg`.
3. **Presentation type resolution**: `parse_printf_presentation_type` determines the final conversion (decimal, hexadecimal, floating-point, etc.).
4. **Formatting**: The argument is rendered through `printf_arg_formatter`.

This pipeline resides within `detail::vprintf`, which serves as the implementation core for public APIs including `fmt::printf`, `fmt::sprintf`, and related functions.

## Practical Code Examples

The following examples demonstrate POSIX positional syntax in fmtlib:

```cpp
// Positional arguments: %2$d prints the second argument, %1$s prints the first.
fmt::printf("%2$d %1$s\n", "hello", 42);
// Output: 42 hello

// Positional width: *3$ takes the width from the third argument.
fmt::printf("%*3$d\n", 0, 0, 5, 123);
// Output:   123 (5-character wide field)

// Positional precision: .*4$f takes the precision from the fourth argument.
fmt::printf("%.*4$f\n", 0, 0, 0, 3, 2.71828);
// Output: 2.718

```

These patterns allow format strings to reference arguments in any order and to source dynamic widths or precisions from specific parameter positions.

## Summary

- **Primary implementation** resides in [`include/fmt/printf.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/printf.h), specifically within the `parse_header` function (lines 330-381) and the `get_arg` lambda (lines 13-23).
- **Argument indexing** uses one-based numbering in format strings (e.g., `%2$d`) that converts to zero-based internal indices during retrieval.
- **Positional specifiers** support both direct value substitution and indirect width/precision references using the `*N$` and `.*N$` syntax.
- **Validation** occurs through `parse_ctx.check_arg_id()`, ensuring explicit indices remain within bounds before argument retrieval.
- **Fallback behavior** defaults to sequential argument processing when no explicit index is provided (indicated by negative index values).

## Frequently Asked Questions

### What is the POSIX positional printf extension?

The POSIX positional printf extension is a formatting syntax enhancement that allows format strings to specify exactly which argument to use for a particular conversion specifier by placing a decimal index and `$` immediately after the `%` (e.g., `%2$d`). It also permits width and precision to be taken from specific arguments using `*N$` and `.*N$` syntax, enabling argument reordering and dynamic formatting control.

### How does fmtlib handle mixed positional and non-positional arguments?

According to the source code in [`include/fmt/printf.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/printf.h), fmtlib requires format strings to use either all positional or all non-positional arguments; mixing styles within a single format string results in an error. The `get_arg` lambda distinguishes between modes by checking whether `arg_index` is negative (sequential) or positive (explicit), with `parse_ctx` tracking the next sequential position only when no explicit indices are present.

### Can I use positional arguments for width and precision in fmtlib?

Yes, fmtlib fully supports positional width and precision specifiers. You can write `%*3$d` to use the third argument as the field width, or `%.*4$f` to use the fourth argument as the precision for a floating-point conversion. The `parse_header` function at lines 330-381 handles these cases by detecting the `$` character after the asterisk and numeric index.

### Where is the positional argument parsing logic located in the fmt source code?

The core parsing logic resides in [`include/fmt/printf.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/printf.h) within the `parse_header` function (lines 330-381) for extracting indices and the `get_arg` lambda (lines 13-23) for resolving them. Additional supporting infrastructure appears in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h), which defines `format_specs` and `parse_context` that the printf implementation reuses for argument management and validation.