天天看點

《C語言解惑》一1.3 邏輯操作符和增量操作符

本節書摘來自異步社群《c語言解惑》一書中的第1章,第1.3節,作者 傅道坤,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

請問,下面這個程式的輸出是什麼?

《C語言解惑》一1.3 邏輯操作符和增量操作符

輸出:

《C語言解惑》一1.3 邏輯操作符和增量操作符

解惑1.3 邏輯操作符和增量操作符

初始值:x = 2, y=1, z=0

x = x&&y || z  按照操作符的優先級和關聯規則進行綁定。

x = (x&&y) || z

x = ((x&&y) || z)

(x = ((x&&y) || z))

(x = ((true&&true) || z))   邏輯操作符的求值順序是從左到右。邏輯操作符的操作數如果是0,則解釋為false;如果是非零值,則解釋為true。

(x = (true || z))   隻有兩個操作數都是true,邏輯與(&&)的結果才會是true;其他情況的求值結果都将是false。

(x = (true ||任意值))  隻要有一個操作數是true,那麼不管另一個操作數是什麼,邏輯或(||)的結果都将是true。是以,我們不必再對這個表達式繼續求值了。

(x = true)

(x = 1)

1

再談define:這個程式裡的define語句與前一個程式裡的define語句有所不同:這個程式裡的“print”是一個帶參數的宏。在遇到帶參數的宏時,c語言的預處理器将分兩步進行替換:先把宏定義裡的形式參數替換為實際參數,再把宏調用替換為宏定義體。

在這個程式裡,“print”宏有一個形式參數int。“print<code>(x)”是使用實際參數“x”進行的“print”調用。在擴充“print”調用的時候,c語言預處理器會先把宏定義裡的所有“int”替換為“x”,再把宏調用“print</code>(x)”替換為結果字元串“printf``("%dn", x)”。請注意,形式參數int并不是比對單詞“printf”裡的“int”字元的。這是因為宏定義裡的形式參數是辨別符——具體到這個例子,形式參數int隻對辨別符int進行比對和替換。

初始值:x = 1, y=1, z=0

x || ! y&amp;&amp;z

x || (! y)&amp;&amp;z  對操作符和操作數進行綁定。

x || ((! y)&amp;&amp;z)

(x || ((! y)&amp;&amp;z))

(true || ((! y)&amp;&amp;z))  按從左到右的順序求值。

(true ||任意值)

true,即1

初始值:x = 1,y=1

z = x ++ - 1

z = (x ++) – 1  對操作符和操作數進行綁定。

z = ((x ++) - 1)

(z = ((x ++) - 1))

(z = (1 - 1)),此時x=2  出現在操作數右邊的“++”操作符是所謂的“後”遞增操作符:先在表達式裡用該操作數完成有關的計算,再對它進行遞增。

(z = 0)

z += - x ++ + ++ y

z += - (x ++) + (++ y)   一進制操作符的關聯是從右到左,因而“++”操作符将先于一進制操作符“-”得到綁定。(事實上,如果先去綁定“-”操作符的話,這個表達式将無法成立。這是因為“++”和“--”操作符都要求以一個變量(更準确地說,以一個“左值”[1])作為其操作數。“x”是一個左值,但“-x”不是。)

z += (- (x ++)) + (++ y)

z += ((- (x ++)) + (++ y))

(z += ((- (x ++)) + (++ y)))

(z += ((-2) + 2)),此時x=3, y=2

(z += 0)

(z = 0 + 0)

按照從内到外的順序依次求值。

關于記号:計算機程式的源代碼文本是由一系列記号構成的,而編譯一個程式的第一項工作就是把那些記号一個一個地分解開。這在絕大多數場合都沒有什麼困難,但有些字元序列可能會讓人感到困惑。比如說,如果上面這個例子裡的表達式有一部分根本沒有空格——就像下面這樣:

x+++++y

那麼,這個沒有空格的表達式與有空格的表達式還會是等價的嗎?

為避免産生二義性,如果一個字元串能夠解釋為多個操作符,c語言編譯器将按照“構成操作符的字元個數越多越好”的原則來作出選擇。根據這一原則,“x+++++y”解釋為:

x++ ++ + y

而這已經不是一個合法的表達式了。

初始值:x = 3,z=0

z = x / ++ x

z = x / (++ x)

z = (x / (++ x))

(z = (x / (++ x)))

如果你還像以前那樣按照從内到外的順序對這個表達式進行求值,即先對x進行遞增,然後作為除數、用x作被除數去進行除法計算。問題是:作為被除數的x到底是幾?是3還是4?換個問法,被除數到底是遞增前的x值,還是遞增後的x值?請注意,c語言并沒有對這種“副作用”作出明确的規定,而是由c編譯器的編寫者決定的[2]。這個例子的教訓是:如果你無法斷定會不會産生副作用,那麼就盡量不要寫這樣的表達式。

繼續閱讀