Die Formatierungsbibliothek in C++20: Details zum Formatstring
![](https://heise.cloudimg.io/width/700/q75.png-lossy-75.webp-lossy-75.foil1/_www-heise-de_/imgs/18/4/5/3/5/5/6/7/hello_world_dirtymono-92cf51a984a85758.jpeg)
(Bild: DirtyMono/Shutterstock)
Der zweite Teil der Serie zu Formatstrings in C++20 beschäftigt sich mit der Breite, der Genauigkeit und dem Datentyp der Formatspezifikation.
In meinem letzten Artikel "Die Formatierungsbibliothek in C++20: Der Formatstring [1]" habe ich einige der Formatspezifikationen des Formatstrings vorgestellt. Heute beende ich die Abhandlung dazu.
![](https://heise.cloudimg.io/width/696/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/5/3/5/5/6/7/TimelineCpp20CoreLanguage-e7502c4e54c375e9.png)
Im heutigen Artikel werde ich über die Breite, die Genauigkeit und den Datentyp der Formatspezifikation schreiben. Wenn Du mehr über das Argument id, die Füllzeichen, die Ausrichtung, die Vorzeichen und die alternative Form wissen willst, lies meinen vorherigen Artikel: "Die Formatierungsbibliothek in C++20: Der Formatstring [2]".
Breite und Genauigkeit
Man kann die Breite und die Genauigkeit eines Arguments angeben. Die Breite kann auf Zahlen und die Genauigkeit auf Fließkommazahlen und Zeichenketten angewendet werden. Bei Fließkommazahlen gibt die Genauigkeit die Formatierungsgenauigkeit an; bei Zeichenketten gibt die Genauigkeit an, wie viele Zeichen verwendet werden und wie die Zeichenkette letztendlich abgeschnitten wird. Wenn die Genauigkeit größer ist als die Länge der Zeichenkette, hat dies keine Auswirkungen auf die Zeichenkette.
- Breite: Man kann entweder eine positive Dezimalzahl oder ein Ersetzungsfeld (
{}
oder{n}
) verwenden. Wenn angegeben, gibtn
die Mindestbreite an. - Genauigkeit: Man kann einen Punkt (.) gefolgt von einer nicht-negativen Dezimalzahl oder ein Ersetzungsfeld verwenden.
Ein paar Beispiele sollen helfen, die Grundlagen zu verstehen:
// formatWidthPrecision.cpp
#include <format>
#include <iostream>
#include <string>
int main() {
int i = 123456789;
double d = 123.456789;
std::cout << "---" << std::format("{}", i) << "---\n";
std::cout << "---" << std::format("{:15}", i)
<< "---\n"; // (w = 15)
std::cout << "---" << std::format("{:}", i)
<< "---\n"; // (w = 15) // (1)
std::cout << '\n';
std::cout << "---" << std::format("{}", d) << "---\n";
std::cout << "---" << std::format("{:15}", d)
<< "---\n"; // (w = 15)
std::cout << "---" << std::format("{:}", d)
<< "---\n"; // (w = 15)
std::cout << '\n';
std::string s= "Only a test";
std::cout << "---" << std::format("{:10.50}", d)
<< "---\n"; // (w = 10, p = 50) // (2)
std::cout << "---" << std::format("{:{}.{}}", d, 10, 50)
<< "---\n"; // (w = 10, p = 50) // (3)
std::cout << "---" << std::format("{:10.5}", d)
<< "---\n"; // (w = 10, p = 5)
std::cout << "---" << std::format("{:{}.{}}", d, 10, 5)
<< "---\n"; // (w = 10, p = 5)
std::cout << '\n';
std::cout << "---" << std::format("{:.500}", s)
<< "---\n"; // (p = 500) // (4)
std::cout << "---" << std::format("{:.{}}", s, 500)
<< "---\n"; // (p = 500) // (5)
std::cout << "---" << std::format("{:.5}", s)
<< "---\n"; // (p = 5)
}
Das w
-Zeichen im Quellcode steht für die Breite; ebenso das p
-Zeichen für die Genauigkeit.
Hier sind ein paar interessante Beobachtungen zu dem Programm: Es werden keine zusätzlichen Leerzeichen hinzugefügt, wenn die Breite mit einem Ersetzungsfeld angegeben wird (1). Wenn eine Genauigkeit verwendet wird, die größer ist, als die Länge des angezeigten double
(2 und 3), spiegelt die Länge des angezeigten Wertes die Genauigkeit wider. Diese Beobachtung gilt nicht für eine Zeichenkette (4 und 5).
![](https://heise.cloudimg.io/width/572/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/5/3/5/5/6/7/formatWidthPrecision-df8073948175f78c.png)
Zusätzlich lässt sich die Breite und die Genauigkeit parametrisieren.
// formatWidthPrecisionParametrized.cpp
#include <format>
#include <iostream>
int main() {
std::cout << '\n';
double doub = 123.456789;
std::cout << std::format("{:}\n", doub); // (1)
std::cout << '\n';
for (auto precision: {3, 5, 7, 9}) {
std::cout << std::format("{:.{}}\n",
doub,
precision); // (2)
}
std::cout << '\n';
int width = 10;
for (auto precision: {3, 5, 7, 9}) {
std::cout << std::format("{:{}.{}}\n",
doub,
width,
precision); // (3)
}
std::cout << '\n';
Das Programm formatWidthPrecisionParametrized.cpp
stellt das Double doub
auf verschiedene Arten dar. (1) wendet die Standardeinstellung an. (2) variiert die Genauigkeit von 3 bis 9. Das letzte Argument des Formatstrings geht in das innere {}
des Formatspezifiers {:.{}}
. Schließlich wird in (3) die Breite der angezeigten Double-Werte auf 10 gesetzt.
![](https://heise.cloudimg.io/width/547/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/5/3/5/5/6/7/formatWidthPrecisionParametrized-a997bbe49896fe8f.png)
Datentyp
Im Allgemeinen leitet der Compiler den Typ des verwendeten Wertes ab. Aber manchmal möchte man den Datentyp angeben. Dies sind die wichtigsten Datentypen:
Zeichenketten: s
Ganzzahlen:
b
: BinärformatB
: wieb
, aber Basispräfix ist0B
d
: dezimales Formato
: oktales Formatx:
hexadezimales FormatX
: wiex
, aber das Basispräfix ist0X
char
und wchar_t
:
b, B, d, o, x, X
: wie Ganzzahlen
bool:
s
:true
oderfalse
b, B, d, o, x, X
: wie Ganzzahlen
Fließkommazahlen:
e
: ExponentialformatE
: wiee
, aber der Exponent wird mitE
geschriebenf, F
: Festkomma; die Genauigkeit beträgt 6g, G
: Genauigkeit 6, aber der Exponent wird mitE
geschrieben
Zeiger:
p
: hexadezimale Schreibweise seiner Adresse
Nur die Datentypen void
, const void
und std::nullptr_t
sind gültig. Wer die Adresse eines beliebigen Zeigers anzeigen will, muss ihn in (const) void*
umwandeln.
double d = 123.456789;
std::format("{}", &d); // ERROR
std::format("{}", static_cast<void*>(&d)); // okay
std::format("{}", static_cast<const void*>(&d)); // okay
std::format("{}", nullptr); // okay
Mit den Datentypen kann man einen int
ganz einfach in einem anderen Zahlensystem darstellen.
// formatType.cpp
#include <format>
#include <iostream>
int main() {
int num{2020};
std::cout << "default: " << std::format("{:}", num)
<< '\n';
std::cout << "decimal: " << std::format("{:d}", num)
<< '\n';
std::cout << "binary: " << std::format("{:b}", num)
<< '\n';
std::cout << "octal: " << std::format("{:o}", num)
<< '\n';
std::cout << "hexadecimal: " << std::format("{:x}", num)
<< '\n';
}
![](https://heise.cloudimg.io/width/379/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/4/5/3/5/5/6/7/FormatType-1c3d76639f6f4724.png)
Wie geht es weiter?
Bisher habe ich die elementaren Datentypen und Strings formatiert. Natürlich lassen sich auch benutzerdefinierte Typen formatieren. Das wird das Thema meines nächsten Artikels sein. (rme [3])
URL dieses Artikels:
https://www.heise.de/-9615593
Links in diesem Artikel:
[1] https://www.heise.de/blog/Die-Formatierungsbibliothek-in-C-20-Der-Formatstring-9610546.html
[2] https://www.heise.de/blog/Die-Formatierungsbibliothek-in-C-20-Der-Formatstring-9610546.html
[3] mailto:rme@ix.de
Copyright © 2024 Heise Medien