How to Use fmtlib for Character and String Presentation Types
The fmt library selects character presentation via presentation_type::chr when using the 'c' conversion, and string presentation via presentation_type::string when using the 's' conversion, with both types parsed in include/fmt/core.h and handled during final formatting in include/fmt/format.h.
The fmtlib/fmt repository provides a modern C++ formatting library that routes arguments through a strongly-typed format_spec structure. When you use fmtlib for character and string presentation types, the library inspects your format specifier at compile time (or runtime for dynamic strings) to determine whether to treat the argument as a single Unicode code point or as a sequence of characters.
Understanding Presentation Types in fmtlib
Every format operation in fmtlib begins by parsing the format string into a format_spec object. This structure contains a presentation_type enum that dictates how the argument should be rendered.
According to the source code in include/fmt/core.h (around line 654), the presentation_type enum defines distinct values for different formatting behaviors. For text output, two values are critical:
presentation_type::chr– Indicates single-character formattingpresentation_type::string– Indicates string formatting
The parser determines which type to use by examining the conversion character in your format specifier. Inside include/fmt/core.h, the parse_presentation_type function handles this logic:
case 'c': // character conversion
return parse_presentation_type(presentation_type::chr, integral_set);
case 's': // string conversion
return parse_presentation_type(presentation_type::string,
cstring_set | string_set);
Once parsing completes, the format_spec stores the selected type (accessible via specs.type()), which the main formatting engine in include/fmt/format.h uses to route output through the appropriate branch in fmt::vformat.
Character Presentation Type (presentation_type::chr)
How Character Formatting Works
When you specify the 'c' conversion, fmtlib treats the argument as a single Unicode code point regardless of whether you pass an integer or a character type. The parse_presentation_type function sets the internal type to presentation_type::chr, and the final output routine in include/fmt/format.h renders the value using the appropriate character encoding (UTF-8, UTF-16, or UTF-32).
This presentation type accepts any integral value that represents a valid code point. The library performs the necessary encoding conversion automatically based on the output context.
Character Formatting Examples
#include <fmt/core.h>
int main() {
// Format integer 65 as the character 'A'
fmt::print("Char: {:c}\n", 65); // Output: Char: A
// Use width and alignment with character presentation
fmt::print("Padded: {:>5c}\n", 'Z'); // Output: Padded: Z
// Character presentation with fill character
fmt::print("Filled: {:*^3c}\n", 'X'); // Output: Filled: *X*
}
The character type respects width, alignment, and fill specifiers, allowing you to pad single characters within a fixed field.
String Presentation Type (presentation_type::string)
How String Formatting Works
The 's' conversion triggers presentation_type::string, which fmtlib applies to char pointers, std::string, std::string_view, and any type implicitly convertible to a C-style string. During parsing in include/fmt/core.h, the parser selects this type when it encounters the 's' conversion or when the argument type matches the string type sets (cstring_set | string_set).
In include/fmt/format.h, the vformat implementation checks specs.type() and routes string arguments through dedicated output routines that respect precision (maximum characters to display) and width (minimum field size).
String Formatting Examples
#include <fmt/core.h>
#include <string>
int main() {
// Basic string presentation
std::string name = "fmt";
fmt::print("Library: {:s}\n", name); // Output: Library: fmt
// Truncate with precision
fmt::print("Truncated: {:.3s}\n", "fmtlib");
// Output: Truncated: fmt
// Combine width, alignment, and precision
fmt::print("|{:<10.5s}|\n", "formatted");
// Output: |format |
// C-style string pointer
const char* msg = "hello";
fmt::print("Message: {:s}\n", msg); // Output: Message: hello
}
Format Specifier Reference
Both presentation types support the full fmtlib specification syntax:
| Specifier | Effect on Character (:c) |
Effect on String (:s) |
|---|---|---|
| Width | Minimum field width; pads with fill character | Minimum field width; pads if string is shorter |
| Precision | No effect (always single character) | Maximum number of characters to output |
| Align | < left, > right, ^ center |
< left, > right, ^ center |
| Fill | Any character preceding align | Any character preceding align |
The include/fmt/printf.h header provides C-style printf compatibility and maps %c and %s to these same presentation types internally.
Summary
- Character presentation (
presentation_type::chr) is selected by the'c'conversion ininclude/fmt/core.hand renders integral values as single Unicode code points. - String presentation (
presentation_type::string) is selected by the's'conversion and handlesstd::string,std::string_view, and C-style strings through the formatting engine ininclude/fmt/format.h. - Both types support width, alignment, and fill specifications, but only string presentation respects precision for truncation.
- The parsing logic in
parse_presentation_typedetermines the presentation type at format-string compile time, whilefmt::vformatdispatches to the appropriate output routine based onspecs.type().
Frequently Asked Questions
What is the difference between {:c} and {:s} in fmtlib?
{:c} treats the argument as a single character code point, accepting integers or character types and rendering exactly one Unicode character, while {:s} treats the argument as a string sequence, accepting pointer types, std::string, or std::string_view and rendering the full sequence (subject to precision limits). The underlying enum values presentation_type::chr and presentation_type::string in include/fmt/core.h distinguish these behaviors.
Can I use precision specifiers with character presentation types?
No, precision specifiers have no effect on the 'c' conversion. Since presentation_type::chr always represents a single code point, the precision field is ignored. If you need to limit output with character types, you must handle the truncation before passing the value to the formatter, or use string presentation if the data is stored as a string.
How does fmtlib handle Unicode when using character presentation?
The fmt library treats character presentation as a Unicode code point and encodes it according to the output context (UTF-8, UTF-16, or UTF-32). When you pass an integer to {:c}, fmtlib validates that it represents a valid code point and performs the necessary encoding conversion in the output routines defined in include/fmt/format.h, ensuring correct multi-byte character generation.
Are these presentation types compatible with C printf-style formatting?
Yes, fmtlib maintains compatibility through include/fmt/printf.h. The %c conversion maps to presentation_type::chr and %s maps to presentation_type::string, routing through the same underlying formatting machinery as the modern {} syntax. However, the modern format specifiers provide additional capabilities like named arguments, compile-time checking, and more precise alignment controls that printf-style formatting cannot express.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →