Fragen zu std::istringstream
-
Hallo.
Ich bin noch recht neu in C++ und haette da einige Fragen zur Umwandlung eines Strings in eine Zahl.Ich weiss, dass ich eine Zahl aus einem String per std::istringstream lesen kann.
std::string s("999999999"); // 999.999.999 std::istringstream ss(s); int i; ss >> i; std::cout << i;Dieser Code funktioniert nicht mehr, da die Zahl wohl zu gross ist:
std::string s("9999999999"); // 9.999.999.999 std::istringstream ss(s); int i; ss >> i; std::cout << i;Als Ergebnis erhalte ich hier "-858993460". Bedeutet das, dass es hier einen Ueberlauf gab? Wie kann ich das pruefen?
Gibt es eine Moeglichkeit zu pruefen welcher Datentyp fuer die Konvertierung am besten geeignet waere?
Wie kann ich pruefen, ob eine Konvertierung fehlschlag und was genau die Ursache dafuer war? (z.B. wegen eines ungueltigen Zeichens)
-
Bedeutet das, dass es hier einen Ueberlauf gab?
Nein. Das Ergebnis einer solchen Operation ist undefiniert (? Der Standard ist ein bisschen unklar an der Stelle). Bei meiner Implementierung kommt beispielsweise INT_MAX dabei heraus.
Wie kann ich das pruefen?
Wenn das Lesen fehlschlägt, weil die Zahl zu groß/klein für den Datentyp ist, wird das failbit des Streams gesetzt.
Ich schreibe bewusst ganz allgemein "Stream" anstatt istringstream, denn alle Streams verhalten sich gleich. Alles was du hier lernst, kannst du auch auf alle anderen Streamobjekte anwenden.Gibt es eine Moeglichkeit zu pruefen welcher Datentyp fuer die Konvertierung am besten geeignet waere?
Und was wurdest du machen, wenn du es wüsstest? Worauf willst du hinaus?
Wie kann ich pruefen, ob eine Konvertierung fehlschlag und was genau die Ursache dafuer war?
Die Streams haben verschiedene Fehlerflags, guck sie dir mal an:
http://www.cplusplus.com/reference/iostream/ios_base/iostate/
Was die genaue Ursache war ist ein bisschen haariger rauszufinden. Eigentlich gar nicht so wirklich. Du müsstest schon vorher die Daten komplett aus dem Stream lesen, irgendwo speichern und diese dann in einen anderen Stream stopfen, aus diesem lesen und im Fehlerfall kannst du dann in den Originaldaten nach der Ursache suchen. Wieder die Frage: Was würde es dir denn nützen? Reicht es nicht zu wissen, dass ein Fehler aufgetreten ist?
-
SeppJ schrieb:
Bedeutet das, dass es hier einen Ueberlauf gab?
Nein. Das Ergebnis einer solchen Operation ist undefiniert (? Der Standard ist ein bisschen unklar an der Stelle). Bei meiner Implementierung kommt beispielsweise INT_MAX dabei heraus.
22.4.2.1.2 num_get virtual functions [facet.num.get.virtuals]
:::
Stage 3: The sequence of chars accumulated in stage 2 (the field) is converted to a numeric value by the rules of one of the functions declared in the header <cstdlib>:
— For a signed integer value, the function strtoll.
— For an unsigned integer value, the function strtoull.
— For a floating-point value, the function strtold.
The numeric value to be stored can be one of:
— zero, if the conversion function fails to convert the entire field. ios_base::failbit is assigned to err.
— the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.
— the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err.
— the converted value, otherwise.
The resultant numeric value is stored in val.
-
Falls du größere zahlen erlauben willst, dann kannst du auch statt int ein long long nehmen.
-
Interessant. Wie würdest du dann die Konvertierung die in Kapitel 27.6.1.2.2 damit in Verbindung bringen? Das ist die Stelle auf die ich mich bezog und ich finde das ganze Kapitel etwas undeutlich geschrieben.
Die von dir zitierte Stelle würde natürlich auch bedeuten, dass die Standardbibliothek des Threaderstellers hier nicht standardkonform ist. Kurzes Googlen ergibt, dass -858993460 == 0xcccccccc und dies wohl ein üblicher Fehlerwert bei Microsoft ist.
edit: Meine Kapitelnummern sind noch aus C++98, deine offensichtlich C++11 (da es 22.4 in C++98 gar nicht gibt). In C++11 ist das Kapitel auf das ich mich bezog nun ziemlich eindeutig. Der Wert hat min bzw. max zu sein (oder das richtige Ergebnis, wenn es passt). Frage hat sich somit erledigt, den 0xcccccccc kann man dann meinetwegen auf die undeutliche Formulierung in C++98 schieben.
edit: Für die, die es interessiert:
C++98,operator >>( short & val ):typedef num_get < charT , istreambuf_iterator < charT , traits > > numget ; iostate err = 0; long lval ; use_facet < numget >( loc ). get (* this , 0 , * this , err , lval ); if ( err == 0) && ( lval < numeric_limits < short >:: min () || numeric_limits < short >:: max () < lval )) err = ios_base :: failbit ; setstate ( err );C++11:
typedef num_get<charT,istreambuf_iterator<charT,traits> > numget; iostate err = ios_base::goodbit; long lval; use_facet<numget>(loc).get(*this, 0, *this, err, lval); if (lval < numeric_limits<short>::min()) { err |= ios_base::failbit; val = numeric_limits<short>::min(); } else if (numeric_limits<short>::max() < lval) { err |= ios_base::failbit; val = numeric_limits<short>::max(); } else val = static_cast<short>(lval); setstate(err);
-
SeppJ schrieb:
Interessant. Wie würdest du dann die Konvertierung die in Kapitel 27.6.1.2.2 damit in Verbindung bringen? Das ist die Stelle auf die ich mich bezog und ich finde das ganze Kapitel etwas undeutlich geschrieben.
Die von dir zitierte Stelle würde natürlich auch bedeuten, dass die Standardbibliothek des Threaderstellers hier nicht standardkonform ist. Kurzes Googlen ergibt, dass -858993460 == 0xcccccccc und dies wohl ein üblicher Fehlerwert bei Microsoft ist.
Wie üblich bezog ich mich auf den neuen Standard.
In C++03 ist die Konvertierung durch num_get über scanf definiert, damit folgt dort undefiniertes Verhalten für zu große oder zu kleine Werte (C99 7.19.6.2/10).
-
camper schrieb:
Wie üblich bezog ich mich auf den neuen Standard.
In C++03 ist die Konvertierung durch num_get über scanf definiert, damit folgt dort undefiniertes Verhalten für zu große oder zu kleine Werte (C99 7.19.6.2/10).Joah, hab's bemerkt. Siehe meinen Beitrag oben, der in der Zwischenzeit reichlich länger geworden ist.