web-dev-qa-db-ja.com

std :: cin(gcc、clangが同意しない)を介して、負の値をunsignedに読み取ることは失敗する必要がありますか?

例えば、

#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に設定し、ストリームにフェイルビットを設定しません。

31
Lingxi

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​::​failbiterrに割り当てられます。

これらはすべて、「変換されるフィールド」について説明しており、によって返される実際の値ではないことに注意してください。 std::strtoull。ここでのフィールドは、実際には文字'-', '1'の拡張シーケンスです。

フィールドはunsignedで表すことができない値(-1)を表すため、戻り値はUINT_MAXであり、フェイルビットはstd::cinで設定する必要があります。


1clangは、実際にはC++ 17の直前でした。これは、上記の引用の3番目の箇条書きが次のとおりであったためです。

-フィールドがvalで表すには大きすぎる負の値を表す場合、最も負の表現可能な値、または符号なし整数型の場合はゼロ。 ios_base::failbiterrに割り当てられます。

2std::strtoullULLONG_MAXを返します。なぜなら(@NathanOliverに感謝)— C/7.22.1.4.5:

サブジェクトシーケンスが期待される形式で、基数の値がゼロの場合、最初の桁から始まる文字のシーケンスは、6.4.4.1の規則に従って整数定数として解釈されます。 [...]サブジェクトシーケンスがマイナス記号で始まる場合、変換の結果の値は否定されます(戻り値の型)。

18
Holt

_std::cin >> n_コマンドの意図されたセマンティクスが説明されています ここ (明らかに、この操作ではstd::num_get::get()が呼び出されます)。この関数、特にw.r.tにはいくつかのセマンティクスの変更があります。 C++ 11で、次にC++ 17で、0を配置するかどうかの選択。

完全にはわかりませんが、これらの違いが、あなたが見ている異なる行動の原因である可能性があると思います。

0
einpoklum