zurück zum Artikel

Die Formatierungsbibliothek in C++20: Details zum Formatstring

Rainer Grimm

(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.

Modernes C++ – Rainer Grimm
Rainer Grimm

Rainer Grimm ist seit vielen Jahren als Softwarearchitekt, Team- und Schulungsleiter tÀtig. Er schreibt gerne Artikel zu den Programmiersprachen C++, Python und Haskell, spricht aber auch gerne und hÀufig auf Fachkonferenzen. Auf seinem Blog Modernes C++ beschÀftigt er sich intensiv mit seiner Leidenschaft C++.

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]".

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.

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).

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.

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:

char und wchar_t:

bool:

Fließkommazahlen:

Zeiger:

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';

}

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