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