首頁  >  文章  >  後端開發  >  「C 程式語言」中的函數鍊是否表現出未指定的行為?

「C 程式語言」中的函數鍊是否表現出未指定的行為?

Barbara Streisand
Barbara Streisand原創
2024-10-23 18:19:25367瀏覽

Does Function Chaining in

《C 程式語言》中的程式碼片段是否表現出未定義的行為?

有問題的C 程式碼,由Bjarne Stroustrup 在《C 程式語言》第四版中提供C 程式語言」使用函數鏈來修改字串:

<code class="cpp">void f2() {
    std::string s = "but I have heard it works even if you don't believe in it";
    s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, "");

    assert(s == "I have heard it works only if you believe in it");
}</code>

此程式碼演示如何連結update() 操作來更改字串s。 >

雖然程式碼看起來很簡單,但它涉及未指定的順序求值,特別是對於涉及函數呼叫的子表達式 雖然它不會呼叫未定義的行為(因為所有副作用都發生在函數呼叫內),但它確實表現出未指定的行為。 ) 沒有明確定義。值順序:

我們可以看到以下子表達式是不確定排序的(由括號中的數字表示):

s.replace(0, 4 , "") (1)

s.find("偶數") (2)
s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, "");

s.replace(s.find("偶數"), 4, "僅") ( 3)

    s.find("不要") (4)
  • s.replace(s.find("不要"), 6, "") (5)
  • 每對括號內的表達式都是有序的(例如,2 在3 之前),但它們可以按彼此不同的順序進行計算。 2 之間以及表達式1 和4 之間。在某些情況下,replace() 呼叫的計算方式會導致預期的行為,而在其他情況下,計算順序會以意外的方式更改字串。情況:
    • 在某些實作中,例如 Clang,replace(0, 4, "") 在 find("even") 和 find(" don't") 之前進行評估。這確保了後續的替換呼叫對修改後的字串進行操作,產生正確的結果。
    • 在其他實作中,例如 GCC 和 Visual Studio,find("even") 和 find(" don't")可以在replace(0, 4, "")之前進行評估。這可能會導致不正確的結果,因為 find 呼叫對原始的、未修改的字串進行操作,可能會找到與預期不同的位置。

    指定與未指定的行為

    需要注意的是,此程式碼呼叫未定義的行為。未定義的行為通常涉及存取未初始化的變數或嘗試存取其邊界之外的記憶體。在這種情況下,所有副作用都發生在函數呼叫內,且程式碼不會存取無效的記憶體位置。

    但是,程式碼確實表現出未指定的行為,這表示C 標準沒有定義子運算式的求值。這可能會導致不同的編譯器產生不同的結果,甚至是同一程式的不同運行。

    建議的更改

    C 標準委員會已認識到此問題並提出更改以細化表達式求值順序慣用語C .對C 20 中的[expr.call]p5 的建議更改指定“後綴表達式在表達式清單中的每個表達式和任何預設參數之前排序”,這將消除此程式碼中未指定的行為。

以上是「C 程式語言」中的函數鍊是否表現出未指定的行為?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn