[英]Operator precedence in C for the statement z=++x||++y&&++z
[英]Why does “++x || ++y && ++z” calculate “++x” first, even though operator “&&” has higher precedence than “||”
為什么++x || ++y && ++z
++x || ++y && ++z
首先計算++x
,即使運算符&&
的優先級高於||
?
因為&&
優先級高於||
,這意味着你的表達相當於:
++x || (++y && ++z)
因此,在程序甚至開始評估&&
的結果之前,它必須評估++x
以確定是否是||
的右手操作數。 甚至應該評估(邏輯二元運算符是“短路”,這意味着如果左側足以確定結果,它們不會評估右側)。 這里沒有什么可疑的或編譯器特定的。 此表達式的行為完全由C標准指定,並且在任何編譯器上都是相同的。 如果x
, y
和z
都是相同的變量,它甚至會起作用,因為||
和&&
引入序列點。
放松 , R和其他人解釋了真正發生的事情。 那么我來補充一下:
你的問題的前提是錯誤的。 &&
具有更高優先級的事實並不意味着必須在具有較低優先級的表達式中的任何操作數之前評估圍繞它的操作數。 即使在特殊情況下||
的短路 和&&
這不一定是這樣。
例如,考慮a=b+c+d*e
; *
具有比+
更高的優先級,但這並不意味着必須在b+c
之前評估d*e
。 它只是意味着在將產品作為一個整體添加到表達式之前必須對其進行評估。 編譯器可以將此表達式計算為temp1=d*e
, temp2=b+c
, a=temp1+temp2
或者它可以評估temp1=b+c
, temp2=d*e
, a=temp1+temp2
。 兩者都同樣有效。
具有||
的短路行為 和&&
,對評估順序有一些額外的限制。
作為旁注:一般來說,我會避免編寫這樣的代碼。 我可以很容易地看到另一個程序員試圖閱讀這段代碼,對於增量何時發生以及什么時候不發生而感到困惑。 好吧,也許如果你使用真正的變量名稱,它看起來不會那么奇怪。
我偶爾會依靠短路來防止副作用。 喜歡
if (!eof() && readNextInt()>0)
如果我們已經在文件末尾,我依靠短路來防止閱讀,或者
if (confirmDelete==YES && deleteEntry()!=-1)
我依靠第一個測試來對錯誤進行短路,所以當我不應該這樣做時我不會刪除。 但這些例子對我來說似乎很簡單,我希望任何有能力的程序員都能看到我在做什么。 但是當這些例子變得神秘時,我認為它需要被打破。 考慮
if (customerType==RETAIL || lastDepositAmount()>100.00)
如果lastDepositAmount()
有副作用,那么如果customerType
是零售,那么這種副作用將永遠不會發生。 我不認為這對讀者來說一定是顯而易見的。 (部分原因是函數名稱暗示它正在檢索數據而不執行任何更新,部分原因是客戶類型與存款金額之間沒有明顯的關系 - 這聽起來像兩個獨立的事情。)不可否認,這是主觀。 但是如果有疑問,請選擇簡單明了而不是簡單的性能提升。 總是選擇簡單和清晰, “嘿,這是一個很酷的使用一個不起眼的功能,任何讀這篇文章的人都會對如何聰明地理解語言這一點感到印象深刻” 。
這里有可怕的錯誤答案。
此表達式的評估順序不依賴於實現 。 它定義明確!
因為&&
綁定高於||
,這個表達式相當於++x || (++y && ++z)
++x || (++y && ++z)
。 此外,還有&&
和||
是短路的 ,所以如果表達式的左側足以確定值,則永遠不會評估右側。
這是什么情況? 好吧,我們知道False && a
總是解析為False
,無論a的值是a
,特別是即使a
不是單個值而是復雜表達式。 因此,我們不評價a
都沒有。 同樣, True || a
True || a
總是解析為True
。
這導致在這個例子中非常明確的評估順序: 首先是 ++x
, 然后是 (如果有的話) ++y
然后 (再次:如果有的話) ++z
。
使用波蘭樹數據結構評估運算符,如圖所示,它是深度優先評估算法。 讓我們給出操作的名稱:A = ++ x B = ++ y C = ++ z D = B && CE = C || D評估順序:A,B,C,D,E。當然,C有一個優化,如果A為真,那么E將被評估為真而不評估BC和D.同樣,如果B為假,則C贏了不進行評估以優化評估速度。
++具有最高優先級,作為其預增量。 這意味着此操作的結果值將傳遞給二元運算符。 然而有趣的是++ x的短路或其他的短路。 如果++ x為真,則其余部分可能根本不會完成。
評價的優先順序和順序不是一回事 ,特別是在這種情況下。 所有優先級都告訴您表達式應該被解析為
++x || (++y && ++z)
IOW,這意味着OR一起的表達式是++x
和(++y && ++z)
。 它並不意味着(++y && ++z)
之前將被評估 ++x
。
對於邏輯運算符||
和&&
,評估總是從左到右( 在線C標准 ,第6.5.13和6.5.14節)。 對於任何表達
a || b
a
將被完全評估; b
將不會被評價除非的結果a
為0(想到a
站在對++x
和b
站在為++y && ++z
)。 同樣,對於任何表達
a && b
a
將被完全評估; b
將不會被評價除非的結果a
不為0。
因此,對於您的情況,首先計算表達式++x
。 如果結果為0, 那么將僅評估++y && ++z
。
||
和&&
是特別的,因為評估的順序保證是從左到右。 對於按位運算符或算術運算符,情況並非如此。 例如,在表達式中
++x + ++y * ++z
表達式++x
, ++y
和++z
可以按任何順序進行評估; 所有優先級告訴你的是(y+1) * (z+1)
的結果將被添加到x+1
的結果中。
前兩個答案很好地解釋了......我會指出|| 是“OrElse”。
如果左側是真的,右側不會被觸及。 如果右側是假的,&&(AndAlso)的左側不會被觸及。
如果您希望雙方都增加,請使用| 和&。
http://msdn.microsoft.com/en-us/library/2h9cz2eb(v=VS.80).aspx
如果編譯的代碼可以根據另一個表達式的結果繞過一個表達式的評估,則稱邏輯操作是短路的。 如果第一個表達式求值的結果確定了操作的最終結果,則無需計算第二個表達式,因為它無法更改最終結果。 如果繞過的表達式很復雜,或者涉及過程調用,則短路可以提高性能。
MSDN有表格顯示部分是如何“(未評估)”。
如果第1部分確定性地預先確定結果,為什么要觸摸第2部分?
自從我使用C以來已經有很長一段時間了,但如果我沒記錯的話,++是一元運算符,它總是先於二元運算符。 如果你考慮它會有意義。
如果您的操作對訂單敏感,則不應依賴於感知的操作員優先級,因為不同的編譯器(以及相同版本的不同版本)可以以不同方式實現優先級。
無論如何b定義++ x意味着x必須在使用之前遞增,因此你可以期望它在執行時具有高優先級。
不不不
if (++x || ++y && ++z) { /* ... */ }
是
++x; ++y; ++z; if (x || (y && z)) { /* ... */ }
同行投訴后編輯 :)
是!
if (is_data_valid(x, y, z)) process_data(&x, &y, &z);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.