Zum Beispiel,
#include <iostream>
int main() {
unsigned n{};
std::cin >> n;
std::cout << n << ' ' << (bool)std::cin << std::endl;
}
Wenn -1
eingegeben wird, gibt clang 6.0.00 0
aus, während gcc 7.2.04294967295 1
ausgibt. Ich frage mich, wer richtig ist. Oder vielleicht sind beide für den Standard korrekt, spezifiziert dies nicht? Im Fehlerfall nehme ich an, dass (bool)std::cin
als falsch bewertet wird. clang 6.0.0 schlägt auch die Eingabe -0
fehl.
Ich denke, dass beide in C++ 17 falsch sind1 und dass die erwartete Ausgabe sein sollte:
4294967295 0
Dies ist jedoch schwer vom Standard zu verstehen ...
Der Standard sagt - [facet.num.get.virtuals # 3.3] :
Die in Stufe 2 (das Feld) angesammelte Folge von Zeichen wird durch die Regeln einer der im Header deklarierten Funktionen in einen numerischen Wert umgewandelt.
<cstdlib>
:
Für einen vorzeichenbehafteten ganzzahligen Wert die Funktion
strtoll
.Für einen vorzeichenlosen Integerwert ist die Funktion
strtoull
.Für einen Gleitkommawert ist die Funktion
strtold
.
Wir greifen also auf std::strtoull
zurück, das zurückkehren muss2 ULLONG_MAX
und nicht errno
gesetzt (was beide Compiler tun).
Aber im selben Block (Hervorhebung gehört mir):
Der zu speichernde numerische Wert kann einer der folgenden sein:
null, wenn die Konvertierungsfunktion nicht das gesamte Feld konvertiert.
der positivste (oder negativste) darstellbare Wert, wenn das -Feld, das in einen vorzeichenbehafteten Ganzzahlentyp konvertiert werden soll, einen Wert darstellt, der zu groß ist, um positiv (oder negativ) in
val
dargestellt zu werden.der positivste darstellbare Wert, wenn das -Feld, das in einen vorzeichenlosen Integer-Typ umgewandelt werden soll, einen Wert darstellt, der nicht in
val
dargestellt werden kann.ansonsten der umgerechnete Wert.
Der resultierende numerische Wert wird in
val
gespeichert. Wenn die Konvertierungsfunktion nicht das gesamte Feld konvertiert oder wenn das Feld einen Wert außerhalb des Bereichs der darstellbaren Werte darstellt, wirdios_base::failbit
err
zugewiesen.
Beachten Sie, dass alle diese Informationen über "zu konvertierendes Feld" und nicht über den von std::strtoull
zurückgegebenen Wert sprechen. Das Feld hier ist eigentlich die verbreiterte Folge des Zeichens '-', '1'
.
Da das Feld einen Wert (-1) darstellt, der nicht durch eine unsigned
dargestellt werden kann, sollte der zurückgegebene Wert UINT_MAX
sein und das Failbit sollte auf std::cin
gesetzt sein.
1clang
war eigentlich vor C++ 17 richtig, da der dritte Punkt im obigen Zitat:
- der negativste darstellbare Wert oder Null für einen vorzeichenlosen Integer-Typ, wenn das Feld einen Wert darstellt, der zu groß ist, um in
val
dargestellt zu werden.ios_base::failbit
isterr
zugewiesen.
2 std::strtoull
gibt ULLONG_MAX
zurück, weil (danke @NathanOliver) - C/7.22.1.4.5:
Wenn die Subjektsequenz die erwartete Form hat und der Wert von base Null ist, wird die Zeichenfolge, die mit der ersten Ziffer beginnt, als Ganzzahlkonstante gemäß den Regeln von 6.4.4.1 ..__ interpretiert. [...] Wenn die Betreffsequenz mit einem Minuszeichen beginnt, wird der aus der Konvertierung resultierende Wert negiert (im Rückgabetyp).
Die beabsichtigte Semantik Ihres std::cin >> n
-Befehls wird beschrieben hier (da anscheinend std::num_get::get()
für diese Operation aufgerufen wird). In dieser Funktion wurden einige Änderungen der Semantik vorgenommen, insbesondere w.r.t. die Wahl, ob 0 oder nicht platziert werden soll, in C++ 11 und dann erneut in C++ 17.
Ich bin nicht ganz sicher, aber ich glaube, dass diese Unterschiede für das unterschiedliche Verhalten verantwortlich sind, das Sie sehen.