具有不可預測循環行為的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, ...」的無限重複。經調查,比較 di < 1。 4 無法正常工作,導致無限循環。
停用看似無害的賦值 delta = mc[di] 神奇地修復了問題,產生預期的輸出。這個簡單的操作會導致什麼問題?
深入研究未定義的行為
解開這個謎團的關鍵在於理解未定義的行為。賦值 delta = mc[di] 會在循環的最後一次迭代中觸發對數組的越界訪問。雖然許多編譯器可能根據最佳化策略假設沒有未定義的行為,但這種假設本質上是有缺陷的。
開啟最佳化的 GCC 可以在假設不存在未定義行為的情況下積極優化循環。這種最佳化導致錯誤的推斷:di
因此,循環變成無限循環,因為條件 di
揭開編譯器的內部運作方式
仔細檢查最佳化後的程式碼顯示 di
與此行為相反,帶有 -fsanitize=undefined 的 Clang 會捕捉這種情況。然而,具有相同標誌的 GCC 在此特定實例中無法發出警告。
未定義行為的危險
未定義行為,由 C 標準定義,允許出現不可預測的結果,包括完全無視情況。應不惜一切代價避免未定義的行為,因為它可能導致編譯器不一致和意外的執行時間行為。
為了避免此類陷阱,程式設計師應該努力編寫符合預期語意的定義良好的程式碼。編譯器也應該實施適當的防禦措施,以提醒開發人員潛在的未定義行為。
以上是為什麼為複雜變數賦值會導致 C 程式中的無限循環,即使它看起來像是一個看似無害的操作?的詳細內容。更多資訊請關注PHP中文網其他相關文章!