8

私は次のコードを持っています:

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    string a = "a";
    for(unsigned int i=a.length()-1; i+1 >= 1; --i)
    {
        if(i >= a.length())
        {
            cerr << (signed int)i << "?" << endl;
            return 0;
        }
    }
}

完全に最適化して MSVC でコンパイルすると、得られる出力は "-1?" です。デバッグ モード (最適化なし) でコンパイルすると、出力が得られません (予期される)。

標準では、符号なし整数が予測可能な方法でオーバーフローすることが保証されているため、i = (unsigned int)(-1)、i+1 = 0 の場合、ループ条件 i + 1 >= 1 は失敗します。代わりに、テストは何とか合格しています。これはコンパイラのバグですか、それともどこかで未定義のことをしていますか?

4

4 に答える 4

8

2001 年にこの問題が発生したことを覚えています。まだ残っていることに驚いています。はい、これはコンパイラのバグです。

オプティマイザーが見ている

i + 1 >= 1;

理論的には、すべての定数を同じ側に置くことでこれを最適化できます。

i >= (1-1);

iは符号なしであるため、常に 0 以上になります。

このニュースグループのディスカッションはこちら.

于 2009-03-24T02:44:59.237 に答える
4

ISO14882:2003、セクション 5、パラグラフ 5:

式の評価中に、結果が数学的に定義されていないか、その型の表現可能な値の範囲内にない場合、そのような式が定数式 (5.19) でない限り、動作は未定義です。 -形成された。

(私のものを強調してください。) そうです、動作は未定義です。標準では、整数オーバー/アンダーフローの場合の動作は保証されていません。

編集:標準は、他の場所で問題がわずかに矛盾しているようです。

セクション 3.9.1.4 は次のように述べています。

符号なしと宣言された符号なし整数は、2 n を法とする算術法則に従うものとします。ここで、n は、整数の特定のサイズの値表現のビット数です。

しかし、セクション 4.7.2 および .3 は次のように述べています。

2) 宛先の型が符号なしの場合、結果の値はソース整数と一致する最小の符号なし整数です (モジュロ 2 n で、n は符号なしの型を表すために使用されるビット数です)。[注: 2 の補数表現では、この変換は概念的なものであり、ビット パターンに変更はありません (切り捨てがない場合)。]

3) 宛先タイプが符号付きの場合、宛先タイプ (およびビットフィールド幅) で表現できる場合、値は変更されません。それ以外の場合、値は実装定義です。

(私のものを強調してください。)

于 2009-03-24T02:52:47.610 に答える
1

確かではありませんが、おそらくバグを犯していると思います。

問題は、コンパイラがコントロールを処理する方法にあると思われますfor。オプティマイザが次のことを行っていると想像できます。

for(unsigned int i=a.length()-1; i+1 >= 1; --i)   // As written

for (unsigned int i = a.length()-1; i >= 0; --i) // Noting 1 appears twice

for (unsigned int i = a.length()-1; ; --i)   // Because i >= 0 at all times

それが起こっているかどうかは別の問題ですが、オプティマイザを混乱させるには十分かもしれません。

おそらく、より標準的なループの定式化を使用した方がよいでしょう。

for (unsigned i = a.length()-1; i-- > 0; )
于 2009-03-24T02:50:47.070 に答える
0

はい、Visual Studio 2005 でこれをテストしたところ、Debug と Release で動作が明らかに異なります。2008年に修正されるのだろうか。

興味深いことに、size_t (.length の結果) から unsigned int への暗黙のキャストについて不平を言いましたが、問題なく悪いコードを生成しました。

于 2009-03-24T02:55:23.750 に答える