所以我正在閱讀不同運算子的順序,我讀到它的&&重要性高于||它,并且它會更快地評估(source)。然后有人問了這段代碼會列印什么的問題:
#include <stdio.h>
int main(){
int a=0, b=0, c=0, d=0;
if(a >0 || b==1 || c--<=0 && d >c--){
printf("if\na:%d\nb:%d\nc:%d\nd:%d\n",a,b,c,d);
}
else{
printf("else\na:%d\nb:%d\nc:%d\nd:%d\n",a,b,c,d);
}
return 0;
}
我認為c-- <= 0 && d > c--將首先評估,這總體上是正確的。在該程序之后,c將等于 -2 并d等于 1。然后它將從左側開始檢查,評估a > 0 || b == 1哪個是真的,a最后b為 1,在條件和之后為 1。所以總條件將是true || true,它是真的,所以我們將列印:
if
a:1
b:1
c:-2
d:1
是的?顯然,沒有。我已經在我的系統(Windows 10)上使用 GCC(Mingw)和在線編譯器(這個)對其進行了測驗,并且都列印了:
if
a:1
b:1
c:0
d:0
我已將條件更改為:if(a >0 || b==1 || (c--<=0 && d >c--) )但兩個地方的輸出完全相同。有什么我不注意的嗎?或者這就像一個錯誤?看起來幾乎是這樣,||并且&&具有相同的優先級,整個事情都是從左側評估的,并且會發生短路等事情。如果我將 b==1部分更改為 b==0,則輸出與我預測的相同。
在此先感謝您的任何幫助:)
uj5u.com熱心網友回復:
本題中的表達:
if(a >0 || b==1 || c--<=0 && d >c--)
是一個可怕的、可怕的表達方式的經典例子,非常不切實際和不切實際,而且很難理解,但它說明了一個非常重要的點:優先級與評估順序不同。
優先級真正告訴我們的是運算子如何與其運算元連接。所以給出簡化的運算式
A || B || C && D
哪兩個子運算式執行第一個||、第二個||和&&實際連接在一起并對其進行操作?如果您是編譯器撰寫者,您可以通過構建一個“決議樹”來回答這些問題,該樹明確顯示哪些子運算式與哪些運算子對應。
因此,給定運算式A || B || C && D,運算式的決議樹是否如下所示:
&&
/ \
|| D
/ \
|| C
/ \
A B
或者像這樣:
||
/ \
A ||
/ \
B &&
/ \
C D
或者像這樣:
||
/ \
/ \
|| &&
/ \ / \
A B C D
要回答這個問題,我們不僅要知道 的優先級&&高于||,還要知道||是左結合的。鑒于這些事實,運算式
A || B || C && D
被決議就好像它已經被寫入一樣
(A || B) || (C && D)
因此,結果是我展示的三個候選決議樹中的第三個:
||
/ \
/ \
|| &&
/ \ / \
A B C D
但是現在我們可以真正了解||and&&運算子的“短路”行為將如何應用。那個“頂部”||將評估它的左側,然后,如果它是假的,也評估它的右側。同樣,下層||將評估其左側。所以,不管怎樣,A首先要得到評估。對于原始問題中的運算式,對應于a > 0。
現在,a >0是假的,所以我們將不得不評估B,即 b == 1。現在,這是真的,所以第一個的結果||是“真”。
所以第二個(頂部)||運算子的結果也是“真”。
因此,||根本不必評估頂部運算子的右側。
因此,&&根本不會評估包含的整個子運算式。
因此,即使&&具有最高優先級,它最終還是最后被考慮,并且(因為涉及左側的內容||并且是真的)它最終根本沒有得到評估。
最重要的是,正如我開始所說的那樣,優先級并不能決定評估的順序。
此外,如果其他地方沒有說明,這種保證的從左到右的行為僅適用于||and&&運算子(并且以不同的方式適用于三元?:運算子)。如果運算式是
A B C * D
它會不會是真實的,正如我剛才所說,“無論什么時候,A是會得到第一評估”。對于像 and*這樣的算術運算子,沒有辦法知道是先計算左邊還是右邊。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/364734.html
