短路求值
求值策略 |
---|
短路求值(Short-circuit evaluation; minimal evaluation; McCarthy evaluation; 又稱最小化求值)[1],是一種邏輯運算符的求值策略。只有當第一個運算數的值無法確定邏輯運算的結果時,才對第二個運算數進行求值。例如,當AND的第一個運算數的值為false時,其結果必定為false;當OR的第一個運算數為true時,最後結果必定為true,在這種情況下,就不需要知道第二個運算數的具體值。在一些語言中(如Lisp),默認的邏輯運算符就是短路運算符,而在另一些語言中(如Java,Ada),短路和非短路的運算符都存在。對於一些邏輯運算,如XOR,短路求值是不可能的。
短路表達式x AND y
,事實上等價於條件語句:if x then y else false
。短路表達式x OR y
,則等價於條件語句:if x then true else y
。
C語言和C++
C語言和C++語言標准強制規定了||
和&&
短路求值語義以及求值順序。從而,下述這樣的包含安全檢查的代碼是非常常見的:
char* pChar = 0;
// some actions which may or may not set pChar to something
if ((pChar != 0) && (*pChar != '\0')) {
// do something useful
}
C99語言標準的Section 6.5.13 Logical AND operator規定:
(4). Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares equal to 0, the second operand is not evaluated. 翻譯:於二元位與運算符&不同,&&運算符保證從左到右求值,第一操作數求值後有一個順序點。如果第一操作數比較等於0,則第二操作數不再求值。
類似地,section 6.5.14 Logical OR operator有類似規定。C++語言標准有同樣規定。但如果重載了||
和&&
運算符,則僅是普通運算符。
考慮以下使用C語言寫的例子:
int a = 0;
if (a && myfunc(b)) {
do_something();
}
在這個例子中,最小化計算使得myfunc(b)
永遠不會被調用。這是因為 a
等於false,而false AND q無論q是什麼總是得到false。這個特性允許兩個有用的編程結構。首先,不論判別式中第一個子判別語句要耗費多昂貴的計算,總是會被執行,若此時求得的值為 false,則第二個子判別運算將不會執行,這可以節省來自第二個語句的昂貴計算。再來,這個結構可由第一個子判別語句來避免第二個判別語句不會導致運行時錯誤。例如對以下使用C語言寫的例子而言,最小化計算可以避免對空指針進行存取。
void * p = NULL;
int ret;
/* ... */
if(p && ret = func(p) ){
/* 或者另一種更清晰的寫法是if( (p != NULL) && (ret = func(p)) ) */
/* ... */
}
/* ... */
當使用最小化計算時,很重要的一點是得知表示式取值的順序。某些編程語言中確保有一致的取值順序。例如:C語言、Java、Perl、Python和Ruby等。
它不過是下面語句的一種更加緊湊的表示形式罷了。
if (cond_a) {
if (expensive_or_dangerous_cond_b) {
...
}
}
註釋
- ^ Peter Hofer, Peter Fischer: Lexikon der Informatik. 15. Auflage. Springer, Berlin 2010, ISBN 3-642-15125-6, S. 81 (eingeschränkte Vorschau in der Google-Buchsuche).
參考文獻
- Michael L. Scott: Programming Language Pragmatics. 3. Auflage. Elsevier LTD, Oxford 2009, ISBN 0-12-374514-4, S. 239 (eingeschränkte Vorschau in der Google-Buchsuche).