Je pense que les deux sont erronés en C++17. 1 et que le résultat attendu devrait être :
4294967295 0
Bien que la valeur renvoyée soit correcte pour les dernières versions des deux compilateurs, je pense que l'option ios_base::failbit
devrait être fixé, mais je pense aussi qu'il y a une confusion sur la notion de champ à convertir dans la norme qui pourrait expliquer les comportements actuels.
La norme dit - [facet.num.get.virtuals#3.3] :
La séquence de caractères accumulée à l'étape 2 (le champ) est convertie en une valeur numérique par les règles de l'une des fonctions déclarées dans l'en-tête <cstdlib>
:
-
Pour une valeur entière signée, la fonction strtoll
.
-
Pour une valeur entière non signée, la fonction strtoull
.
-
Pour une valeur à virgule flottante, la fonction strtold
.
Donc nous nous rabattons sur std::strtoull
qui doit retourner 2 ULLONG_MAX
et ne pas mettre errno
dans ce cas (ce que font les deux compilateurs).
Mais dans le même bloc ( accentuation est le mien) :
La valeur numérique à mémoriser peut être l'une des suivantes :
-
zéro, si la fonction de conversion ne convertit pas le champ entier.
-
la valeur représentable la plus positive (ou négative), si la champ à convertir à un type d'entier signé représente une valeur trop grande positive (ou négative) pour être représentée en val
.
-
la valeur représentable la plus positive, si le champ à convertir à un type d'entier non signé représente une valeur qui ne peut pas être représentée en val
.
-
la valeur convertie, sinon.
La valeur numérique résultante est stockée dans val
. Si la fonction de conversion ne convertit pas le champ entier, ou si le champ représente une valeur en dehors de la plage des valeurs représentables, ios_base::failbit
est affecté à err
.
Remarquez que toutes ces discussions sur le "champ à convertir" et non la valeur réelle renvoyée par std::strtoull
. Le champ ici est en fait la séquence élargie de caractères '-', '1'
.
Puisque le champ représente une valeur (-1) qui ne peut pas être représentée par un champ unsigned
la valeur renvoyée devrait être UINT_MAX
et le failbit doit être réglé sur std::cin
.
<sup>1 </sup><code>clang</code> était en fait juste avant C++17 parce que le troisième point de la citation ci-dessus l'était :
- la valeur représentable la plus négative ou zéro pour un type d'entier non signé, si le champ représente une valeur négative trop grande pour être représentée en <code>val</code> . <code>ios_base::failbit</code> est affecté à <code>err</code> .
<sup>2 </sup><a href="http://en.cppreference.com/w/cpp/string/byte/strtoul" rel="noreferrer"><code>std::strtoull</code></a> renvoie à <code>ULLONG_MAX</code> car (merci @NathanOliver) - C/7.22.1.4.5 :
Si la séquence du sujet a la forme attendue et que la valeur de la base est zéro, la séquence de caractères commençant par le premier chiffre est interprétée comme une constante entière selon les règles du 6.4.4.1. [...] Si la séquence sujet commence par un signe moins, la valeur résultant de la conversion est niée (dans le type de retour).
4 votes
Que signifie "échouer" ici ? Vous ne pouvez pas obtenir -1, c'est sûr.
0 votes
J'ai essayé de répondre à cette question... c'est un terrier de lapin. Au minimum, pourriez-vous ajouter quel standard C++ vous compilez, il y a tellement de changements "jusqu'à", "après" etc. que ne pas le savoir va rendre presque impossible de donner une réponse définitive.
4 votes
@ArndtJonasson Je suppose que "échouer" signifie que
failbit
du flux d'entrée a été défini - et donc la deuxième sortie serait 0 plutôt que 1.0 votes
@RichardCritten Ajout d'une balise C++17.
0 votes
Références supplémentaires : bogue libc++ entraînant le changement de comportement et Question du GTL ce qui a entraîné la modification du C++17. Dans aucun de ces cas, il n'est clair pour moi si failbit doit être activé.