予測できないループ動作を伴う C コンパイルの謎
次のコードは、興味深いコンパイルの問題を示しています。
<code class="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; }</code>
逆予想される出力「0、1、2、3」が終了すると、コードは「0、1、2、3、4、5、...」の無限の繰り返しを生成します。調査すると、比較は
一見無害な代入 delta = mc[di] を無効にすると、魔法のように問題が解決され、意図した出力が生成されます。この単純なアクションが引き起こす問題は何ですか?
未定義の動作を詳しく調べる
この謎を解く鍵は、未定義の動作を理解することにあります。代入 delta = mc[di] は、ループの最後の反復で範囲外の配列へのアクセスをトリガーします。多くのコンパイラーは、最適化戦略に基づいて未定義の動作がないことを前提としていますが、この前提には本質的に欠陥があります。
GCC は、最適化をオンにすると、未定義の動作がないことを前提としてループを積極的に最適化できます。この最適化は、 di
その結果、条件 di
コンパイラーの内部動作の公開
最適化されたコードでは、 di
この動作とは対照的に、-fsanitize=unknown を指定した Clang は、このケースを検出します。ただし、同じフラグを持つ GCC は、この特定のインスタンスでは警告を生成できません。
未定義の動作の危険性
C 標準で定義されている未定義の動作。状況を完全に無視するなど、予測できない結果が生じる可能性があります。未定義の動作は、コンパイラの不整合と予期しない実行時の動作の両方を引き起こす可能性があるため、何としても回避する必要があります。
このような落とし穴を避けるために、プログラマーは、意図されたセマンティクスに準拠した明確に定義されたコードを作成するよう努める必要があります。コンパイラは、潜在的な未定義の動作について開発者に警告するための適切な防御策も実装する必要があります。
以上が一見無害なアクションのように見えるにもかかわらず、複雑な変数に値を代入すると C プログラムで無限ループが発生するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。