# How fmt::format Handles Width, Alignment, and Precision Specifiers in fmtlib

> Understand how fmtlib's fmt::format processes width, alignment, and precision specifiers in three stages. Learn about its internal fmt::format_specs object for effective formatting.

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

---

**fmtlib parses width, alignment, and precision in three distinct stages—fill/align, width, then precision—storing results in a `fmt::format_specs` object defined in [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h) before applying them during the formatting phase.**

The fmt library provides a fast, type-safe alternative to printf-style formatting in C++. According to the fmtlib/fmt source code, `fmt::format` processes format specifiers through a pipeline that populates a compact `format_specs` structure, enabling both compile-time optimization via `constexpr` parsing and runtime flexibility through dynamic arguments.

## The format_specs Storage Structure

All parsed format specifications are stored in the `fmt::format_specs` structure, located in [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h). This class inherits from `basic_specs` and encapsulates three critical fields:
- `align`: An enum indicating left (`<`), right (`>`), center (`^`), or sign-aware (`=`) alignment
- `width`: An integer specifying minimum field width (defaults to `0`)
- `precision`: An integer controlling digit count or character limits (defaults to `-1` for unspecified)

## Stage 1: Parsing Fill and Alignment

The parsing pipeline begins with `detail::parse_align` in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h). This function examines the format string for an optional fill character followed by one of four alignment flags:
- `<` for left alignment
- `>` for right alignment
- `^` for center alignment  
- `=` for sign-aware alignment (places the sign before padding)

The detected alignment is converted to an `align` enum value and written to `specs.align`. If no alignment is specified, the default depends on the argument type.

## Stage 2: Parsing Width

Following alignment processing, `detail::parse_width` (defined in [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h)) extracts the width specifier. This function accepts either a literal decimal integer or a dynamic `*` character. When `*` is encountered, the parser consumes the next argument as the width value. The resulting integer is stored in `format_specs::width`, with `0` indicating no minimum width constraint.

## Stage 3: Parsing Precision

When the parser encounters a dot (`.`), it invokes `detail::parse_precision` (also in [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h)). Similar to width parsing, this accepts either a decimal integer or `*` for dynamic precision from arguments. The parsed value is stored in `format_specs::precision`, where `-1` represents "unspecified" and triggers type-specific default behavior.

## Applying Specifications During Formatting

During the output generation phase, the stored specifications drive padding and truncation logic:

**Width handling** occurs in `detail::write` (approximately line 2280 in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h)). The formatter computes the display width of the formatted value and inserts fill characters until `specs.width` columns are reached.

**Alignment implementation** distributes padding according to `specs.align`:
- Right alignment: padding precedes the value
- Left alignment: padding follows the value
- Center alignment: padding splits evenly on both sides
- Sign-aware alignment: places the sign character first, then pads the numeric portion

**Precision enforcement** varies by data type and is handled in specialized functions within [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) (lines 2190–2340):
- **Integers** (`format_int`): Precision specifies minimum digit count, adding leading zeros when necessary
- **Floating-point** (`format_float`): Controls digits after the decimal point
- **Strings** (`format_string`): Limits the number of characters emitted

## Working Code Examples

```cpp
#include <fmt/core.h>

int main() {
    // Width (right-aligned, default fill is space)
    fmt::print("{:10}\n", 42);          // "        42"

    // Left alignment
    fmt::print("{:<10}\n", 42);         // "42        "

    // Center alignment with custom fill character
    fmt::print("{:#^10}\n", 42);        // "####42####"

    // Sign-aware alignment (padding after sign)
    fmt::print("{:=10}\n", -42);        // "-        42"

    // Precision for floating-point numbers
    fmt::print("{:.2f}\n", 3.14159);    // "3.14"

    // Precision for strings (truncate)
    fmt::print("{:.5}\n", "abcdefg");   // "abcde"

    // Dynamic width and precision from arguments
    fmt::print("{:*>{}} {:.{}f}\n", 42, 10, 3.14159, 6, 2);
    // Output: "******42 3.14"
}

```

## Key Implementation Files

| File | Role |
|------|------|
| [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h) | Defines `format_specs` (inheriting from `basic_specs`) and parsing helpers `parse_width`, `parse_precision` |
| [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) | Implements `detail::parse_align` and formatting logic in `detail::write`, `format_int`, `format_float`, and `format_string` |
| `src/format.cc` | Provides concrete instantiations of formatting functions for built-in types |

## Summary

- fmtlib employs three-stage parsing: fill/align, width, then precision, all stored in `format_specs`
- Default values are `0` for width and `-1` for precision (unspecified)
- Dynamic specifiers use `*` to pull values from subsequent arguments at runtime
- `detail::parse_align`, `detail::parse_width`, and `detail::parse_precision` handle the respective parsing stages in [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h) and [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h)
- Padding logic resides in `detail::write` ([`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) line ~2280), which implements alignment rules during output generation
- `constexpr` parsing enables compile-time optimization for constant format strings

## Frequently Asked Questions

### How does fmtlib handle dynamic width and precision specifiers?

When the format string contains `*` for width or precision, `detail::parse_width` and `detail::parse_precision` extract the next argument as an integer value. This dynamic value is stored directly in `format_specs::width` or `format_specs::precision`, allowing runtime control over field dimensions.

### What is the difference between center alignment and sign-aware alignment?

Center alignment (`^`) places the value in the middle with equal padding on both sides. Sign-aware alignment (`=`) places the sign character first, then pads the numeric portion to reach the specified width. Sign-aware alignment only affects numeric types and requires an explicit sign in the format specifier.

### What happens when precision is set to zero versus left unspecified?

An unspecified precision (default `-1`) allows the type-specific formatter to use natural defaults, such as the full string length or default floating-point digits. A precision of `0` explicitly truncates strings to zero characters or removes the decimal portion from floating-point numbers.

### Where does the actual padding occur in the fmtlib source code?

The padding logic resides in `detail::write` within [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) (approximately line 2280). This function consults `format_specs::align` to determine padding placement and repeatedly writes the fill character until the output reaches `format_specs::width` columns.