namespace cpp

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


kennen:include:iostream

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

kennen:include:iostream [2017-03-24 10:11] (aktuell)
Zeile 1: Zeile 1:
 +====== <​iostream>​ ======
 +> Die Verwendung von Flags zur Kontrolle eines Stromzustands
 +> ist jedenfalls eher eine Studie über Implementierungstechniken
 +> als über Schnittstellen-Design.
 +>> ---  Bjarne Stroustrup [C++ 3rd edn, 21.4.1]</​file>​
 +
 +===== Ein- und Ausgabeströme =====
 +C++ bietet eine einheitliche Schnittstelle für [[#​Eingabe|ein-]] ​
 +und [[#​Ausgabe|ausgehende]] Datenströme.
 +Dabei ist es gleichgültig,​ woher die Daten kommen (''​std::​istream''​) ​
 +oder wohin sie gehen (''​std::​ostream''​),​ ob Geräte (Konsole), ​
 +[[fstream|Dateien]] oder [[sstream|Zeichenketten]].
 +Die Kontrolle des [[#​Stromzustand|Stromzustands]],​
 +[[#​Positionierung]]
 +bei wahlfreiem Zugriff und 
 +[[#​Formatierung]]
 +werden einheitlich gehandhabt.
 +
 +|           | Eingabe ​       | Ausgabe ​       | beides|
 +| allgemein | ''​std::​istream''​ | ''​std::​ostream''​ | ''​std::​iostream''​ |
 +| [[fstream|Dateien]] ​ | ''​std::​ifstream'' ​     | ''​std::​ofstream'' ​     | ''​std::​fstream''​ |
 +| [[sstream|Zeichenketten]] | ''​std::​istringstream''​ | ''​std::​ostringstream''​ | ''​std::​stringstream''​ |
 +Stromtypen für ''​wchar_t''​-Zeichen wird noch jeweils ein ''​w''​ vorangestellt.
 +
 +Standardkanäle sind während der Programmlaufzeit mit Stromvariablen verbunden:
 +
 +| ''​std::​cin'' ​ | Eingabe-Konsole (Tastatur)|
 +| ''​std::​cout''​ | Ausgabe-Konsole (Bildschirm)|
 +| ''​std::​cerr''​ | Fehlerausgabe ungepuffert|
 +| ''​std::​clog''​ | Fehlerausgabe gepuffert|
 +
 +==== Ausgabe ====
 +Ausgabeströme ''​std::​ostream''​ nehmen Daten aller Typen entgegen, ​
 +für die der Ausgabeoperator ''<<''​
 +[[..:​operator#​Ein_Ausgabe|überladen]] ist, 
 +und formatieren deren Ausgabe als Folge von Zeichen.
 +Sie schreiben unformatierte Zeichen und Rohspeicher, ​
 +besonders für Binärdateien.
 +
 +<code cpp>
 +void ausgabe(std::​ostream&​ out, double d)
 +
 +  out << d;                           // formatierte Ausgabe
 +  out.put('​ '​); ​                      // Zeichenausgabe
 +  out.write( (char*) &d, sizeof(d) ); // Rohspeicher ​
 +}
 +</​code>​
 +
 +==== Eingabe ====
 +Eingabeströme ''​std::​istream''​ wandeln eingegebene (zulässige) Zeichenfolgen
 +in Werte jener Typen, für die der Eingabeoperator ''>>''​
 +[[..:​operator#​Ein_Ausgabe|überladen]] ist.
 +Führende Leerzeichen werden vom Eingabeoperator ''>>''​ stets verschluckt.
 +Darüber hinaus lassen sich Einzelzeichen ​
 +und Rohspeicher,​ meist aus Binärdateien,​ unformatiert einlesen.
 +
 +<code cpp>
 +void eingabe(std::​istream&​ in, double& d)
 +{
 +  in >> d;                          // formatierte Eingabe ​
 +  char c = in.get(); ​               // Einzelzeichen,​ auch ' ' ​
 +  in.get(c); ​                       // dto.
 +  in.putback(c); ​                   // zurückschieben ​
 +  c = cin.peek(); ​                  // nachschauen,​ aber nicht einlesen
 +  in.read( (char*) &d, sizeof(d) ); // Rohspeicher
 +}
 +</​code>​
 +Das Einlesen von Zeichenketten verlangt besondere Sorgfalt.
 +Führende Leerzeichen werden übergangen, ​
 +das Einlesen endet beim ersten whitespace danach.
 +
 +<code cpp>
 +char str[10]; // lang genug?
 +cin >> str;   // kann und wird schief gehen
 +</​code>​
 +Die Methoden ''​get()''​ und ''​getline()''​
 +lesen auch führende whitespaces in die Zeichenkette ein,
 +begrenzen deren Länge auf maximal ''​n-1''​ Zeichen ​
 +und hängen stets eine '''​\0'''​ an.
 +Werden keine oder ''​n-1''​ Zeichen vor dem Erreichen
 +des ''​ende''​-Zeichens gelesen,
 +wird das ''​failbit''​ gesetzt (siehe [[#​Stromzustand]]).
 +
 +<code cpp>
 +int zeichenketteneingabe(std::​istream&​ in, char* s, int n, char ende='​\n'​)
 +{
 +  in.getline(s,​ n, ende); // ende wird verschluckt
 +  in.getline(s,​ n);       // ende am Zeilenumbruch '​\n'​
 +  in.get(s, n, ende); ​    // ende wird nicht entfernt
 +  in.get(s, n);           // geht schief, wenn schon bei '​\n'​
 +  return in.gcount(); ​    // Anzahl zuletzt gelesener Zeichen
 +}
 +</​code>​
 +
 +==== Stromzustand ====
 +Der Stromzustand von Ein- und Ausgabeströmen ist erfragbar.
 +Er wird intern durch Flags ''​goodbit'', ​
 +''​badbit'',​ ''​failbit''​ und ''​eofbit''​
 +aus der Basisklasse ''​std::​ios_base''​ repräsentiert.
 +Er kann mit ''​rdstate()''​ abgefragt werden.
 +Während ''​clear(state)''​ den Zustand komplett überschreibt,​
 +setzt ''​setstate(state)''​ einzelne Bits zusätzlich.
 +
 +<code cpp>
 +std::​ios_base::​iostate zustand(std::​istream&​ s)
 +{
 +  if (s)        cout << "ok ";
 +  if (s.good()) cout << "gut ";
 +  if (s.eof() ) cout << "noch gut, aber am Dateiende ";
 +  if (s.fail()) cout << "​Aktion schiefgegangen,​ "
 +                        "Strom noch verwendbar ";
 +  if (s.bad() ) cout << "Strom total durcheinander ";
 +  return s.rdstate();​
 +}
 +</​code>​
 +Ein guter Stromzustand ist Voraussetzung,​ aber keine Garantie ​
 +für den Erfolg weiterer Aktionen mit dem Strom.
 +Bei nicht gutem Zustand haben Ein- und Ausgaben keine Wirkung.
 +
 +In der Voreinstellung werfen die Ströme keine [[..:​Ausnahmen|Ausnahmen]]. Mit der Methode ''​exceptions(flags)''​ können sie jedoch dazu gebracht werden, ​
 +bei Fehlern eine von [[.:​system_error|system_error]] ''​std::​ios_base::​failure''​-Ausnahme zu werfen:
 +<code cpp> ​
 +void lass_es_krachen(std::​istream&​ in)
 +{
 +  std::​ios_base::​iostate old = in.exceptions();​ // goodbit bedeutet: keine Ausnahmen werfen
 +  try
 +  {
 +    in.exception(std::​ios_base::​failbit);​ // wirft Ausnahme sofort, falls failbit schon gesetzt ist
 +    int x;
 +    in >> x; // wirft Ausnahme, wenn keine Zahl im Strom ist
 +  }
 +  catch(std::​ios_base::​failure&​ e)
 +  {
 +    std::cerr << "​Fehler in Eingabe: " << e.what() << " Fehlercode: " << e.code() << '​\n';​
 +  }
 +  in.exceptions(old);​
 +}
 +</​code>​
 +Ein- und Ausgabe selbstdefinierter Typen sollten so 
 +[[..:​operator#​Ein- und Ausgabeoperatoren|definiert]] werden,
 +dass Variablen beim Einlesen nicht in einen undefinierten Zustand geraten können ​
 +und der einzulesende Wert erst dann geändert wird, wenn die Eingabe erfolgreich war.
 +
 +<code cpp>
 +struct Punkt { int x, y; };
 +
 +std::​istream&​ operator>>​(std::​istream&​ is, Punkt& p)
 +{
 +  int x, y;
 +  if (is >> x >> y)
 +  {
 +    p.x = x; 
 +    p.y = y;
 +  }
 +  return is;
 +}
 +</​code>​
 +
 +==== Positionierung und wahlfreier Zugriff ====
 +Ströme mit wahlfreiem Zugriff können die Lage der 
 +aktuellen Lese- und Schreibposition im Strom erfragen und ändern.
 +Das ist vor allem für Binärdateien wichtig.
 +Die Position kann absolut oder 
 +relativ zu Anfang ''​std::​ios_base::​beg'', ​
 +aktueller Position ''​std::​ios_base::​cur'' ​
 +oder Ende der Datei ''​std::​ios_base::​end''​ gesetzt werden.
 +
 +<code cpp>
 +long filesize(std::​istream&​ is)
 +{
 +  long pos = is.tellg(); ​          // alte Position merken ​  
 +  is.seekg(0, std::​ios_base::​beg);​ // zum Anfang
 +
 +  long beg = is.tellg(); ​     ​
 +  is.seekg(0, std::​ios_base::​end);​ // zum Ende
 +
 +  long end = is.tellg();
 +  is.seekg(pos); ​                  // alte Position wiederherstellen ​
 +
 +  return end-beg;
 +}
 +</​code>​
 +Bei Ausgabeströmen arbeiten ''​tellp()''​ und ''​seekp()''​ sinngemäß.
 +
 +==== Formatierung ====
 +Das Verhalten der Eingabeströme und das Aussehen der Ausgaben (Formatierung) ​
 +wird durch Schalter (Flags) in der Basisklasse ''​std::​ios_base''​ gesteuert.
 +
 +<code cpp>
 +void formatierung(std::​istream&​ in)
 +{
 +  long alt = in.flags(); ​      // abfragen
 +  long neu = ios_base::​skipws;​ // führende Leerzeichen verschlucken
 +  in.flags(alt | neu);         // Schalter setzen
 +  in.setf(neu); ​               // Flags setzen
 +  in.unsetf(neu); ​             // Flags zurücksetzen  ​
 +}
 +</​code>​
 +Ganzzahlen sind in drei Positionssystemen (Basis, 8, 10, 16) darstellbar.
 +Programmierer verwechseln immer Weihnachten mit Helloween, weil OCT 31 = DEC 25:
 +
 +<code cpp>
 +void ganzzahlbasis(std::​ostream&​ out)
 +{
 +  int i = 25;
 +  out.setf(std::​ios_base::​hex,​ std::​ios_base::​basefield);​
 +  out << i << ' ';
 +  out.setf(std::​ios_base::​oct,​ std::​ios_base::​basefield);​
 +  out << i << ' ';
 +  out.setf(std::​ios_base::​dec,​ std::​ios_base::​basefield);​
 +  out << i << endl;  // Ausgabe: 19 31 25
 +}                      ​
 +</​code>​
 +Die Methode ''​setf(flag,​ mask)''​ wirkt wie
 +''​flags(flags()&​~mask | flag&​mask)''​.
 +Dadurch werden alle Flags in ''​mask''​ zurückgestellt
 +und ''​flag''​ neu gesetzt. ​
 +Dies verhindert, dass zwei einander widersprechende Schalter gleichzeitig gesetzt werden.
 +
 +Folgende Schalterkonstanten aus ''​std::​ios_base''​ beeinflussen die Formatierung:​
 +
 +| ''​left internal right''​ | Ausrichtung bei vorgegebener [[#​width|Ausgabeweite]] in ''​adjustfield''​|
 +| ''​dec hex oct''​ | Ganzzahlbasis für Ein- / Ausgabe in ''​basefield''​|
 +| ''​showbase'' ​   | Ganzzahlbasis bei Ausgabe anzeigen: ''​0x19 031 25''​|
 +| ''​fixed scientific''​ | Fließkomma als Festkomma / mit Exponent ausgeben in ''​floatfield''​|
 +| ''​showpoint''​ | Dezimalpunkt und Nachkommanullen bis zu festgelegter [[#​Genauigkeit]] anzeigen|
 +| ''​showpos'' ​  | positives Vorzeichen immer anzeigen|
 +| ''​uppercase''​ | Ausgabe ''​X''​ und ''​E''​ als Großbuchstabe|
 +| ''​boolalpha''​ | Ausgabe von Wahrheitswerten als Wort entsprechend Locale|
 +| ''​unitbuf'' ​  | nach jeder Ausgabeoperation Puffer leeren|
 +| ''​skipws'' ​   | führende Leerzeichen bei Eingabe mit ''>>''​ verschlucken|
 +
 +Gleitkommazahlen zeigen den Dezimalpunkt und folgende Nullen nur,
 +wenn ''​showpoint''​ gesetzt ist.
 +
 +Die Ausgabegenauigkeit kann mit der Methode ''​precision(n)''​ gesteuert werden.
 +Mit der Standardeinstellung 0 werden bis zu 6 Stellen angezeigt.
 +Im ''​fixed''​-Format ist ''​n''​ die Zahl der Nachkommastellen,​
 +im ''​scientific''​-Format die Gesamtzahl der zählenden Stellen.
 +
 +<code cpp>
 +void genauer(std::​ostream&​ out)
 +{
 +  int n = out.precision();​
 +  out.precision(2*n);​
 +}
 +</​code>​
 +Die Ausgabe eines Wertes nimmt immer mindestens soviele Zeichen ein, 
 +wie zur exakten Ausgabe notwendig sind.
 +Die Ausgabeweite kann für die unmittelbar nächste Ausgabe vergrößert werden.
 +
 +<code cpp>
 +out.width(8);​
 +</​code>​
 +Ist die befohlene Breite größer als notwendig, ​
 +wird die Ausgabezeichenfolge an den Rändern ausgerichtet
 +und mit Füllzeichen (Standardwert '''​ '''​) aufgefüllt.
 +Nach jeder Ausgabe wird die Weite auf den Standardwert 0 zurückgesetzt,​
 +alle anderen Einstellungen sind bleibend.
 +
 +<code cpp>
 +-1.23___ ​ // left (Standard), width(8)
 +-___1.23 ​ // internal
 +___-1.23 ​ // right
 +</​code>​
 +Das Füllzeichen lässt sich abfragen und ändern:
 +
 +<code cpp>
 +char c = out.fill();
 +out.fill('​_'​);​
 +</​code>​
 +
 +==== Formatierung mit Manipulatoren ====
 +Manipulatoren bieten elegantere Schreibweisen zur Formatsteuerung:​
 +
 +<code cpp>
 +int manipuliere(std::​ostream&​ out)
 +{
 +  int i = 123;
 +  double d = 123.456789;
 +  std::cout << std::hex << i << ' '
 +            << std::dec << std::​showpos << i << '​\n';​
 +  std::cout << std::​setw(12) << std::right << i << '​\n';​
 +  std::cout << std::​setw(12) << std::​internal << i << '​\n';​
 +  std::cout << std::​setw(12) << std::​setprecision(3) << d << '​\n';​
 +  std::cout << std::​setw(12) << std::fixed << d << '​\n';​
 +  std::cout << std::​setw(12) << std::​scientific << d << '​\n';​
 +  std::cout << std::​setw(12) << std::​hexfloat << d << '​\n'; ​     // C++11
 +  std::cout << std::​setw(12) << std::​defaultfloat << d << '​\n'; ​ // C++11
 +}
 +</​code>​
 +Es gibt folgende parameterlose Manipulatoren:​
 +
 +| ''​left internal right''​ | Ausrichtung breiter Ausgaben|
 +| ''​dec hex oct''​ | Wechsel der Zahlenbasis bei Ein-/​Ausgabe|
 +| ''​showbase noshowbase''​ | Ganzzahlbasis ''​0...''​ oder ''​0x...''​ ausgeben|
 +| ''​defaultfloat fixed hexfloat scientific''​ | Fließkommaausgabe normal / als Festkommazahl / mit Exponent / mit hexadezimaler Mantisse|
 +| ''​showpoint noshowpoint''​ | Dezimalpunkt und folgende Nullen ausgeben|
 +| ''​showpos noshowpos''​ | positives Vorzeichen ausgeben|
 +| ''​uppercase nouppercase''​ | Groß-/​klein-Ausgabe von ''​X''​ und ''​E''​|
 +| ''​boolalpha noboolalpha''​ | Wahrheitswerte als Wort / Zahl|
 +| ''​endl ends''​ | gibt '''​\n'''​ bzw. '''​\0'''​ aus und leert den Puffer|
 +| ''​flush''​ | leert den Ausgabepuffer|
 +| ''​skipws noskipws''​ | Leerzeichen vor Eingabe verschlucken|
 +| ''​ws''​ | verschluckt whitespaces der Eingabe|
 +
 +Manipulatoren mit Parametern sind in [[iomanip]] definiert:
 +
 +| ''​setbase(base)''​ | Wechsel der Ganzzahlbasis (8, 10, 16)|
 +| ''​setprecision(n)''​ | Genauigkeit von Fließkommazahlen|
 +| ''​setw(width)''​ | Ausgabebreite|
 +| ''​setfill(c)''​ | Füllzeichen festlegen|
 +| ''​setiosflags(f)''​ | Setzen und|
 +| ''​resetiosflags(f)''​ | Rücksetzen von Flags|
 +| ''​quoted(s)''​ | Ein-/​Ausgabe von ''​std::​string s''​ mit Leerzeichen in "​Gänsefüßchen"​ (C++14) |
  
kennen/include/iostream.txt · Zuletzt geändert: 2017-03-24 10:11 (Externe Bearbeitung)