[解決済み] なぜGCCでx86の整数オーバーフローは無限ループを引き起こすのですか?
質問
以下のコードはGCCで無限ループになります。
#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;
}
では、ここからが本題です。 符号付き整数のオーバーフローは技術的に未定義の動作です。しかし、x86 上の GCC は x86 整数命令を使用して整数演算を実装しており、これはオーバーフローでラップされます。
したがって、私は、未定義の動作であるという事実にもかかわらず、オーバーフローでラップされることを期待していました。しかし、明らかにそうではありません。では、私は何を見逃したのでしょうか?
を使ってコンパイルしました。
~/Desktop$ g++ main.cpp -O2
GCCの出力です。
~/Desktop$ ./a.out
536870912
1073741824
-2147483648
0
0
0
... (infinite loop)
最適化を無効にすると、無限ループは発生せず、正しい出力が得られます。Visual Studioもこれを正しくコンパイルし、次のような結果を得ました。
正しい出力です。
~/Desktop$ g++ main.cpp
~/Desktop$ ./a.out
536870912
1073741824
-2147483648
3
他のバリエーションも紹介します。
i *= 2; // Also fails and goes into infinite loop.
i <<= 1; // This seems okay. It does not enter infinite loop.
関連するすべてのバージョン情報です。
~/Desktop$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ..
...
Thread model: posix
gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)
~/Desktop$
というわけで、質問です。 これは GCC のバグでしょうか?あるいは、GCC が整数演算を処理する方法について私が何か誤解していたのでしょうか?
*このバグはCでも再現すると思われるので、Cのタグもつけています(まだ検証していません)。
EDITです。
ループの組み立てはこんな感じです。(私が正しく認識していれば)
.L5:
addl %ebp, %ebp
movl $_ZSt4cout, %edi
movl %ebp, %esi
.cfi_offset 3, -40
call _ZNSolsEi
movq %rax, %rbx
movq (%rax), %rax
movq -24(%rax), %rax
movq 240(%rbx,%rax), %r13
testq %r13, %r13
je .L10
cmpb $0, 56(%r13)
je .L3
movzbl 67(%r13), %eax
.L4:
movsbl %al, %esi
movq %rbx, %rdi
addl $1, %r12d
call _ZNSo3putEc
movq %rax, %rdi
call _ZNSo5flushEv
cmpl $3, %r12d
jne .L5
どのように解決するのですか?
標準では未定義の動作とされている場合。 という意味です。 . あらゆることが起こり得ます。 "Anything" には "usually integers wrap around, but on occasion weird stuff happens" が含まれます。
はい、x86 CPU では、整数は
は通常
は期待通りの方法でラップされます。
これはその例外の一つです。
コンパイラは未定義の動作を起こさないことを想定しており、ループテストを最適化しています。本当に折り返しが欲しいのであれば
-fwrapv
を
g++
または
gcc
を使用します。これにより、明確に定義された(二重補数)オーバーフローセマンティクスが得られますが、パフォーマンスを低下させる可能性があります。
関連
-
[解決済み】C++のGetlineの問題(オーバーロードされた関数 "getline "のインスタンスがない
-
[解決済み】デバッグアサーションに失敗しました。C++のベクトル添え字が範囲外
-
[解決済み】オブジェクト引数のない非静的メンバ関数の呼び出し コンパイラーエラー
-
[解決済み】C++の余分な資格エラー
-
[解決済み] なぜGCCは、速度の代わりにサイズに最適化すると、15-20%速いコードを生成するのですか?
-
[解決済み】なぜこのforループはあるプラットフォームでは終了し、他のプラットフォームでは終了しないのでしょうか?
-
[解決済み】符号なし整数のオーバーフローは定義されているのに、符号あり整数のオーバーフローは定義されていないのはなぜですか?
-
[解決済み] なぜこのループは「warning: iteration 3u invokes undefined behavior」を生成し、4行以上出力するのでしょうか?
-
[解決済み] なぜGCCはほとんど同じCコードに対して根本的に異なるアセンブリを生成するのでしょうか?
-
[解決済み] 強化されたGCC 6オプティマイザは、なぜ実用的なC++コードを壊すのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み] クラスにデフォルトコンストラクタが存在しない。
-
[解決済み】C++の変数はイニシャライザーを持っているが、不完全な型?
-
[解決済み】デバッグアサーションに失敗しました。C++のベクトル添え字が範囲外
-
[解決済み】cc1plus:エラー:g++で認識されないコマンドラインオプション"-std=c++11"
-
[解決済み】Visual Studio 2013および2015でC++コンパイラーエラーC2280「削除された関数を参照しようとした」が発生する
-
[解決済み】クラステンプレートの使用にはテンプレート引数リストが必要です
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み] int i=400*400/400 で結果が 72 になるのはなぜか、データ型が循環しているのか?
-
[解決済み] なぜこのループは「warning: iteration 3u invokes undefined behavior」を生成し、4行以上出力するのでしょうか?