22

悲惨な整数オーバーフローが実際にどの程度なのか疑問に思っていました。次のプログラム例を見てください。

#include <iostream>

int main()
{
    int a = 46341;
    int b = a * a;
    std::cout << "hello world\n";
}

a * a32 ビット プラットフォームではオーバーフローが発生し、整数オーバーフローは未定義の動作を引き起こすため、画面に実際に表示されるという保証はありますhello worldか?


次の標準的な引用に基づいて、質問から「署名済み」の部分を削除しました。

(§5/5 C++03、§5/4 C++11) 式の評価中に、結果が数学的に定義されていないか、その型の表現可能な値の範囲内にない場合、動作は未定義です。

(§3.9.1/4) 宣言された符号なし整数は、unsigned2^n を法とする算術法則に従うものとします。ここで、n は、整数の特定のサイズの値表現のビット数です。これは、結果の符号なし整数型で表現できない結果が、結果の符号なし整数型で表現できる最大値よりも 1 大きい数値を法として減らされるため、符号なし算術演算がオーバーフローしないことを意味します。

4

3 に答える 3

21

コメントで @Xeo が指摘したように (私は実際に最初にC++ チャットで取り上げました):
未定義の動作は本当にそれを意味し、予期しないときにヒットする可能性があります。

これの最良の例は次のとおりです: GCC を使用した x86 で整数オーバーフローが無限ループを引き起こすのはなぜですか?

x86 では、符号付き整数のオーバーフローは単なるラップアラウンドです。したがって、通常、同じことが C または C++ で発生すると予想されます。ただし、コンパイラが介入し、未定義の動作を最適化の機会として使用できます。

その質問から取った例では:

#include <iostream>
using namespace std;

int main(){
    int i = 0x10000000;

    int c = 0;
    do{
        c++;
        i += i;
        cout << i << endl;
    }while (i > 0);

    cout << c << endl;
    return 0;
}

GCC でコンパイルすると、GCC はループ テストを最適化し、これを無限ループにします。

于 2012-01-26T20:47:53.817 に答える
8

ハードウェアの安全機能をトリガーする場合があります。いいえ、保証はありません。

編集: gcc には-ftrapvオプションがあることに注意してください (ただし、私には機能しないようです)。

于 2012-01-26T20:28:27.523 に答える
5

未定義の動作については 2 つの見方があります。奇妙なハードウェアやその他の特殊なケースのために収集するためのビューがありますが、通常は正常に動作する必要があります。そして、何でも起こり得るという見方があります。また、UB ソースによっては、異なる意見を持つものもあります。

オーバーフローに関する UB は、オーバーフローでトラップまたは飽和するハードウェアと、表現間の結果の違いを考慮するためにおそらく導入されているため、この場合の最初のビューについて議論することができますが、オプティマイザーを作成する人々は、次のような見解を非常に重視しています。標準が何かを保証していない場合、実際には何でも起こる可能性があり、結果が意味をなさなくなったとしても、あらゆる自由を使用して、より高速に実行されるマシンコードを生成しようとします。

したがって、未定義の動作が見られた場合は、特定の動作がどれほど合理的に見えても、何かが起こる可能性があると想定してください。

于 2012-01-26T21:05:45.987 に答える