簡體   English   中英

為什么 C 中的邏輯運算符在不需要時不計算整個表達式?

[英]Why do logical operators in C not evaluate the entire expression when it's not necessary to?

我正在為我的計算機體系結構課閱讀我的教科書,我發現了這個說法。

邏輯運算符“ && ”和“ || ”之間的第二個重要區別 ' 與它們的位級對應物 ' & ' 和 ' | ' 是如果表達式的結果可以通過評估第一個參數來確定,則邏輯運算符不評估它們的第二個參數。 因此,例如,表達式a && 5/a永遠不會導致被零除,表達式p && *p++永遠不會導致取消引用空指針。 (Computer Systems: A Programmer's Perspective by Bryant and O'Hallaron,第 3 版,第 57 頁)

我的問題是為什么 C 中的邏輯運算符的行為如此? 使用作者的a && 5/a示例,C 是否不需要評估整個表達式,因為&&要求兩個謂詞都為真? 不失一般性,我同樣的問題適用於他的第二個例子。

短路是一種性能增強,碰巧可用於其他目的。

您說“C 是否不需要計算整個表達式,因為&&要求兩個謂詞都為真?” 但想想吧。 如果&&的左側為假,那么右側的計算結果是否重要? false && truefalse && false ,結果都是一樣的:false。

因此,當確定&&的左側為假時,或確定||的左側時確定為true,右邊的值無所謂,可以跳過。 這消除了評估潛在昂貴的第二次測試的需要,從而使代碼更快。 想象一下,如果右側調用一個函數來掃描整個文件以獲得給定的字符串? 如果第一個測試意味着您已經知道組合答案,您是否不希望跳過該測試?

C 決定超越保證短路到保證評估順序,因為這意味着像您提供的那樣的安全測試是可能的。 只要測試是冪等的,或者僅在不短路時才會出現副作用,則需要此功能。

一個典型的例子是空指針檢查:

if(ptr != NULL && ptr->value) {
    ....
}

如果沒有短路評估,這將在取消引用空指針時導致錯誤。

程序首先檢查左部分ptr != NULL 如果計算結果為false ,則不必計算第二部分,因為很明顯結果將為false

在表達式X && Y ,如果X的計算結果為false ,那么我們知道X && Y將始終為false ,無論Y的值是多少。 因此,無需評估Y

在您的示例中使用此技巧來避免除以0 如果a被評估為false (即a == 0 ),那么我們不評估5/a

它還可以節省大量時間。 例如,在評估f() && g() ,如果對g()的調用f() && g()並且f()返回false ,則不評估g()是一個很好的特性。

C 是否不需要計算整個表達式,因為 && 要求兩個謂詞都為真?

答案:不。為什么在“已經”知道答案的情況下還要工作?

根據邏輯 AND 運算符的定義,引用C11 ,第 6.5.14 章

&&運算符在其兩個操作數比較不等於 0時應產生1 否則,結果為 0。

按照這個類比,對於a && b形式的表達式,如果a的計算結果為 FALSE,無論b的計算結果如何,結果都將為 FALSE。 無論如何,無需浪費機器周期檢查b然后返回 FALSE。

邏輯 OR 運算符也是如此,如果第一個參數的計算結果為 TRUE,則返回值條件已經找到,不需要計算第二個參數。

這只是規則,非常有用。 也許這就是規則的原因。 這意味着我們可以編寫更清晰的代碼。 另一種選擇 - 使用if語句會產生更冗長的代碼,因為您不能直接在表達式中使用if語句。

你已經舉了一個例子。 另一個類似於if (a && b / a)以防止整數除以零,其行為在 C 中未定義就是作者在編寫a && 5/a保護自己a && 5/a

偶爾如果你總是需要評估兩個參數(也許它們調用有副作用的函數),你總是可以使用&| .

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM