例えば、
#include <iostream>
int main() {
unsigned n{};
std::cin >> n;
std::cout << n << ' ' << (bool)std::cin << std::endl;
}
入力-1
の場合、 clang 6.0. は0 0
を出力し、 gcc 7.2. は4294967295 1
を出力します。誰が正しいのだろうか。または多分両方が標準のために正しいですこれを指定していませんか?失敗すると、私は(bool)std::cin
が偽と評価されることを意味すると解釈します。 clang6.0.0も入力-0
に失敗します。
Clang9.0.0およびGCC9.2.0の時点で、Clangの場合はlibstdc ++またはlibc ++のいずれかを使用する両方のコンパイラーは、使用されるC++バージョン(> = C++ 11)に関係なく、上記のプログラムの結果に同意します。と印刷
4294967295 1
つまり、値をULLONG_MAX
に設定し、ストリームにフェイルビットを設定しません。
C++ 17では両方とも間違っていると思います1 期待される出力は次のようになります。
4294967295 0
しかし、これは標準から把握するのは難しいです...
標準によると— [facet.num.get.virtuals#3.3] :
ステージ2(フィールド)で蓄積された文字のシーケンスは、ヘッダー
<cstdlib>
で宣言された関数の1つの規則によって数値に変換されます。
符号付き整数値の場合、関数
strtoll
。符号なし整数値の場合、関数
strtoull
。浮動小数点値の場合、関数
strtold
。
したがって、 std::strtoull
にフォールバックします。2ULLONG_MAX
であり、この場合はerrno
を設定しません(これは両方のコンパイラが行うことです)。
しかし、同じブロックで(emphasisは私のものです):
保存する数値は、次のいずれかになります。
変換関数がフィールド全体を変換しない場合はゼロ。
符号付き整数型に変換されるフィールドが大きすぎる正(または負)の値を表す場合、最も正(または負)の表現可能な値
val
で表されます。符号なし整数型に変換されるフィールドが
val
で表現できない値を表す場合、最も正の表現可能な値。それ以外の場合は、変換された値。
結果の数値は
val
に格納されます。変換関数がフィールド全体を変換しない場合、またはフィールドが表現可能な値の範囲外の値を表す場合、ios_base::failbit
がerr
に割り当てられます。
これらはすべて、「変換されるフィールド」について説明しており、によって返される実際の値ではないことに注意してください。 std::strtoull
。ここでのフィールドは、実際には文字'-', '1'
の拡張シーケンスです。
フィールドはunsigned
で表すことができない値(-1)を表すため、戻り値はUINT_MAX
であり、フェイルビットはstd::cin
で設定する必要があります。
1clang
は、実際にはC++ 17の直前でした。これは、上記の引用の3番目の箇条書きが次のとおりであったためです。
-フィールドが
val
で表すには大きすぎる負の値を表す場合、最も負の表現可能な値、または符号なし整数型の場合はゼロ。ios_base::failbit
はerr
に割り当てられます。
2std::strtoull
はULLONG_MAX
を返します。なぜなら(@NathanOliverに感謝)— C/7.22.1.4.5:
サブジェクトシーケンスが期待される形式で、基数の値がゼロの場合、最初の桁から始まる文字のシーケンスは、6.4.4.1の規則に従って整数定数として解釈されます。 [...]サブジェクトシーケンスがマイナス記号で始まる場合、変換の結果の値は否定されます(戻り値の型)。
_std::cin >> n
_コマンドの意図されたセマンティクスが説明されています ここ (明らかに、この操作ではstd::num_get::get()
が呼び出されます)。この関数、特にw.r.tにはいくつかのセマンティクスの変更があります。 C++ 11で、次にC++ 17で、0を配置するかどうかの選択。
完全にはわかりませんが、これらの違いが、あなたが見ている異なる行動の原因である可能性があると思います。