4

このプログラムを考えてみましょう:

#include <iostream>
#include <string>
#include <sstream>
#include <cassert>

int main()
{
    std::istringstream stream( "-1" );
    unsigned short n = 0;
    stream >> n;
    assert( stream.fail() && n == 0 );
    std::cout << "can't convert -1 to unsigned short" << std::endl;
    return 0;
}

OS X 10.5.6 の gcc (バージョン 4.0.1 Apple Inc. ビルド 5490) でこれを試しましたが、アサーションは true です。-1 を unsigned short に変換できません。

ただし、Visual Studio 2005 (および 2008) では、アサーションは失敗し、結果の n の値は、コンパイラが生成した暗黙的な変換から期待されるものと同じです。つまり、"-1" は 65535、"-2" は 65534 などです。 . しかし、32767 に変換される "-32769" でおかしくなりました。

ここで誰が正しくて誰が間違っているのですか? (そして、-32769 で何が起こっているのか??)

4

3 に答える 3

5

Max Lybbert の投稿で GCC が主張している動作は、iostream 動作を printf/scanf コンバーターにマップする C++ 標準のテーブルに基づいています (少なくともそれは私の読みです)。ただし、g++ の scanf の動作は istream の動作とは異なるようです。

#include <iostream>
#include <cstdio>
using namespace std;;

int main()
{
    unsigned short n = 0;
    if ( ! sscanf( "-1", "%hu", &n ) ) {
        cout << "conversion failed\n";
    }
    else {
        cout << n << endl;
    }
}

実際には 65535 が出力されます。

于 2009-04-24T23:42:59.487 に答える
3

まず、文字列 "-1" を負の数として読み取ることはロケールに依存します (負の数を括弧で囲むことで、ロケールが負の数を識別することが可能です)。 デフォルトの標準は「クラシック」C ロケールです

ロケールの圧倒的な支配的な使用は、ストリーム I/O で暗黙的に行われます。istreamostreamにはそれぞれ独自のロケールがあります。ストリームのロケールは、デフォルトで、ストリームの作成時のグローバルロケールです (6 ページ)。...

最初は、グローバル ロケールは標準の C ロケールであるlocale::classic() (11 ページ) です。

GCC 関係者によると、数値オーバーフローはストリーム入力操作を失敗させることが許可されています(signed int をオーバーフローした負の数について話します)。

[T]libstdc++-v3 の動作は厳密に標準に準拠しています。... 読み取りを試みると、signed int i に収まらず、失敗します

別の回答のおかげで、バグが報告され、この動作が変更されました:

どうやら、符号なしの負の値を正しく解析できなかったようです。修正は簡単です。...

メインラインで修正され、4.4.1 でも修正される予定です。

第二に、整数オーバーフローは一般的に予測可能ですが、公式には未定義の動作であると私は信じています。そのため、-32769" が 32767 に変換される理由はわかりませんが、許可されていると思います。

于 2009-04-24T22:32:22.463 に答える
1

このコードを試してください:

#include <iostream>
#include <string>
#include <sstream>
#include <cassert>

int main()
{
    std::istringstream stream( "-1" );
    std::cout << "flags: " << (unsigned long)stream.flags() << std::endl;
    return 0;
}

私はVS2005でこれを試しました:

flags: 513

そしてcodepad.org(私はg ++を使用していると思います)ではこれは次のようになります:

flags: 4098

これは、gccが別のデフォルトを使用していることを示していますfmtflags。可能な変換を制御するためfmtflags、異なる結果が得られます。

于 2009-04-24T18:27:58.947 に答える