C++コンパイルバグ?
質問
次のようなコードがあります。
#include <iostream>
#include <complex>
using namespace std;
int main() {
complex<int> delta;
complex<int> mc[4] = {0};
for(int di = 0; di < 4; di++, delta = mc[di]) {
cout << di << endl;
}
return 0;
}
0, 1, 2, 3"と出力して止まるかと思いきや、延々と"0, 1, 2, 3, 4, 5, ......"が出力される。
比較のようです
di<4
はうまく機能せず、常に真を返しているように見えます。
もし私がただコメントアウト
,delta=mc[di]
をコメントアウトすると、通常通り "0, 1, 2, 3" が表示されます。無実の代入で何が問題なのでしょうか?
私は イデオン・ドットコム g++ C++14 を -O2 オプション付きで使用しています。
どのように解決するのですか?
これは未定義の動作によるもので、配列にアクセスする際に
mc
にアクセスしています。コンパイラによっては、未定義の動作がないことを前提に、積極的にループの最適化を行う場合があります。ロジックは次のようなものになります。
-
アクセスする
mc
へのアクセスは未定義の動作です。 - 未定義の動作はないとする
-
したがって
di < 4
は常に真であり、そうでなければmc[di]
は未定義の動作を呼び出すからです。
最適化をオンにした gcc で
-fno-aggressive-loop-optimizations
フラグを使用すると、無限ループの動作がなくなります (
ライブを見る
). 一方
最適化されたライブの例ですが、-fn-aggressive-loop-optimizations を使用しない場合
は、あなたが観察したような無限ループの挙動を示します。
A
godboltのライブコードの例
には
di < 4
のチェックは削除され、無条件のjmpに置き換えられました。
jmp .L6
で説明したケースとほぼ同じです。
GCC pre-4.8 は壊れた SPEC 2006 ベンチマークを破壊する
. この記事へのコメントは素晴らしく、一読の価値があります。それは、clang がこの記事の中で
-fsanitize=undefined
を使用した場合、このケースを再現することはできませんが、gccでは
-fsanitize=undefined
では (
ライブを見る
). オプティマイザが未定義の振る舞いを推論するバグとして最も有名なのは、おそらく
Linux カーネルの NULL ポインター チェック除去
.
これは積極的な最適化ですが、C++の標準にあるように未定義の動作であることに注意する必要があります。
この国際規格が何の要件も課さない動作
つまり、本質的に何でも可能であり、それは注釈( 強調 ):
[...]許容される未定義の行動 は、状況を完全に無視することから 予測不可能な結果をもたらす というものから、翻訳中やプログラム実行中に環境に特徴的な文書化された方法で動作する 環境特有の文書化された方法で翻訳またはプログラム実行中に動作する(診断メッセージの発行の有無にかかわらず)。 診断メッセージの発行の有無にかかわらず)、翻訳または実行を終了する(診断メッセージの発行あり)。
gcc から警告を受けるためには
cout
をループの外側に移動させると、次のような警告が表示されます (
ライブを見る
):
warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
for(di=0; di<4;di++,delta=mc[di]){ }
^
というように、OPが何が起こっているのかを理解するのに十分な情報を提供することができたはずです。このような矛盾は、未定義の動作で見られる典型的なタイプです。このような警告が未定義の動作に直面して矛盾している理由をよりよく理解するために なぜ未定義の動作に基づいて最適化するときに警告できないのですか? は良い読み物です。
注意してください。
-fno-aggressive-loop-optimizations
がドキュメント化されているのは
gcc 4.8 リリースノート
.
関連
-
[解決済み】Visual Studio 2015で「非標準の構文。'&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み】C++でランダムな2倍数を生成する
-
[解決済み】C++の変数はイニシャライザーを持っているが、不完全な型?
-
[解決済み】エラー。switchステートメントでcaseラベルにジャンプする
-
[解決済み】ファイルから整数を読み込んで配列に格納する C++ 【クローズド
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)
-
[解決済み】演算子のオーバーロード C++; <<操作のパラメータが多すぎる
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】getline()が何らかの入力の後に使用されると動作しない 【重複あり
-
[解決済み】テンプレートの引数1が無効です(Code::Blocks Win Vista) - テンプレートは使いません。
-
[解決済み] 非常に基本的なC++プログラムの問題 - バイナリ式への無効なオペランド
-
[解決済み】エラー:不完全な型へのメンバーアクセス:前方宣言の
-
[解決済み】エラー:free(): 次のサイズが無効です(fast)。
-
[解決済み】浮動小数点数の乱数生成
-
[解決済み】デバッグアサーションに失敗しました
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較
-
[解決済み] スタックアロケーションにより初期化されていない値が作成された
-
[解決済み] なぜこのループは「warning: iteration 3u invokes undefined behavior」を生成し、4行以上出力するのでしょうか?