オンラインIDEで奇妙な動作をするプログラム


82

私は以下のC ++プログラム(ソース)に出くわしました:

#include <iostream>
int main()
{
    for (int i = 0; i < 300; i++)
        std::cout << i << " " << i * 12345678 << std::endl;
}

それは単純なプログラムのように見え、私のローカルマシンで正しい出力を提供します。

0 0
1 12345678
2 24691356
...
297 -628300930
298 -615955252
299 -603609574

ただし、codechefなどのオンラインIDEでは、次の出力が得られます。

0 0
1 12345678
2 24691356
...
4167 -95167326
4168 -82821648
4169 -7047597

forループが300で終了しないのはなぜですか?また、このプログラムは常にで終了し4169ます。なぜ4169、他の価値はないのですか?


45
おそらく、符号付き整数オーバーフローの動作が未定義であるためです。
eerorika 2018

17
署名されたオーバーフローがUBであることは知っていますが、これは見事な失敗です...
Galik 2018

45
UBが制約されていると想定しないことの良い教訓
MM

12
最初の出力が「正しい出力」であるとあなたが考える理由に興味があります。
軌道上でのライトネスレース

5
@ LightnessRacesinOrbit-まあ、そのリマインダー貴重です!
davidbak 2018

回答:


108

オンラインコンパイラはGCCまたは互換性のあるコンパイラを使用していると仮定します。もちろん、他のコンパイラでも同じ最適化を行うことができますが、GCCのドキュメントではその機能について詳しく説明しています。

-faggressive-loop-optimizations

このオプションは、言語制約を使用してループの反復回数の範囲を導出するようにループオプティマイザーに指示します。これは、ループコードが、たとえば符号付き整数オーバーフローや範囲外の配列アクセスを引き起こすなど、未定義の動作を引き起こさないことを前提としています。ループの反復回数の境界は、ループの展開とピーリング、およびループ終了テストの最適化をガイドするために使用されます。このオプションはデフォルトで有効になっています。

このオプションでは、UBが証明された場合に基づいて仮定を立てることができます。これらの仮定を利用するには、定数畳み込みなど、他の最適化を有効にする必要がある場合があります。


符号付き整数オーバーフローの動作は未定義です。オプティマイザーはi、173を超える値がUBを引き起こすことを証明できましたi。また、UBがないと想定できるため、173を超えることはないと想定することもできます。さらに、それi < 300が常に真であることを証明できます。そのため、ループ条件を最適化することができます。

なぜ4169であり、他の値ではないのですか?

これらのサイトはおそらく、表示する出力行(または文字やバイト)の数を制限しており、たまたま同じ制限を共有しています。


3
コンパイラがi173を超える値のUBがあることを証明できる場合、無意味な最適化を行う代わりに警告を発行しないのはなぜですか?
ジャバウォックの

7
@MichaelWalzそれは1つを放出します。
HolyBlackCat 2018

3
@MichaelWalz:冗長なブールテストを削除することは無意味な最適化ではありません。とても便利なものです。何だろうこと(主に)無意味が無効に余分なコードを追加している/壊れたソースコードの存在下での最適化を元に戻します。

25
@MichaelWalz:コンパイラは、提案されているようにUBを確実に検出できません(ただし、実際にここで行われているように、発生の可能性について警告する場合があります)。代わりに、UBが存在しないことを前提として最善の意図持って進めることができます。これらはおそらく微妙に2つですが、実際には実質的に異なるものです。コンパイラが「ああ!UB!今、私はそのような最適化をオンにすることができます」とは異なります—最適化は常にそこにありました。いつもこういうことをやっています。ただし、プログラムが正しく記述されている限り、セマンティクスの変更を目撃することはありません。
軌道でのライトネスレース

20
例えとして、あなたの家の正面玄関の製造業者は、その中央のどこかに戦術的に配置された金属片があれば、より頑丈になると判断したかもしれません。ドアに穴を開けてドアを間違って使用しない限り、気付くことはありませ
軌道上のライトネスレース

40

「未定義の振る舞いは未定義です。」(c)

codechefで使用されるコンパイラは、次のロジックを使用しているようです。

  1. 未定義の動作は発生しません。
  2. i * 12345678オーバーフローし、UB if i > 173(32ビットを想定int)になります。
  3. したがって、iを超えることはできません173
  4. したがってi < 300、不要であり、に置き換えることができますtrue

ループ自体は無限に見えます。どうやら、codechefは特定の時間が経過した後、プログラムを停止するか、出力を切り捨てるだけです。


11
@ArpanMangal出力の文字数を数えたところ、のよう2^16です。どうやらそれは両方が2^16文字への出力を切り捨てる偶然です。
HolyBlackCat 2018

3
@ArpanMangal:4169のような鼻の悪魔で、現在ideoneとcodechefでパーティーをしています。UBは未定義で、鼻の悪魔を含め、何でもかまいません。真面目な話ですが、UBを分析しようとするのは時間の無駄です。その時間を使って、UBが発生しないようにする方法を見つけてください。
jmoreno 2018

6
@jmorenoコンパイラの設計に興味がある場合は、時間の無駄ではありません
user253751 2018

2
@jmorenoしかし、今回はそれを分析することができました。UBがどのように正確に問題を解決するかを理解することは、UBが受け入れられる場合、その場合を結論付けるのに役立つ可能性があります。
HolyBlackCat 2018

4
@jmoreno宇宙がしていることは(定義上)正しいので、天文学を研究する上でのポイントは何ですか?
user253751 2018

11

最大値はおそらくまだ式が評価しているため、おそらくループ内の174回目の反復で未定義の動作を呼び出してます。これは、符号付き整数オーバーフローがないため、未定義の動作です。したがって、特に最適化フラグが設定されたGCCコンパイラを使用して、UBの影響を観察しています。コンパイラは、次の警告を発行して、これについて警告した可能性があります。forint2147483647174 * 1234567892148147972

warning: iteration 174 invokes undefined behavior [-Waggressive-loop-optimizations]

-O2さまざまな結果を観察するには、()最適化フラグを削除します。


4
未定義の動作は遡及的な影響を与える可能性があることに注意してください。UBは反復174で発生するため、標準では、ループの最初の173回の反復を期待どおりに進める必要はありません。

@Hurkyl確かに。UBが、前のステートメントを含むプログラム全体にUBを表示させるというのは、いくぶん逆説的です。
ロン

12
@ロン:それは逆説的ではありません。プログラムには明確に定義されたセマンティクスがあるか、ないかのどちらかです。限目。C ++コードは、実行する一連の命令ではないことを忘れないでください。それは、あるプログラムの記述
軌道上でのライトネスレース

@LightnessRacesinOrbit:プログラムが、部分的に指定されていないが完全に定義されていないセマンティクスを持つ可能性があります。C標準は、使用する言語が少しあいまいですが、その概念を「BoundedUB」と呼ばれるものに適用しようとします。整数オーバーフローなどを処理する際にコンパイラーに幅広いが無制限ではない自由を許可しても、他の多くの有用な最適化に干渉することはありませんが、信頼できないソースから受信したデータの処理に言語がはるかに適したものになります。
スーパーキャット2018

@supercat:確かに、不特定の振る舞いは未定義の振る舞いと同じではありません。後者について話し合っています
軌道上のライトネスレース

7

コンパイラーは、未定義の動作が発生しないと想定できます。また、符号付きオーバーフローはUBであるため、決してとは想定できません。したがって、チェックi * 12345678 > INT_MAXi <= INT_MAX / 12345678 < 300削除されi < 300ます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.