C語言中,單個&和|,與成雙的&&和||,區別在哪裡?

我只知道是且,||是或,但是看不懂下面書本截圖裡的三個問題的解釋。有大神可以解釋一下這3個問題要如何理解嗎?

書本截圖來源: 嗨翻c語言kindle版(Headfirst C中文版)


邏輯運算與按位運算,不一樣的兩種運算。解釋的挺清楚的了啊……

按位運算是把整數的每個二進位位與另一個整數對應的每個二進位位進行運算,是整數到整數的運算。邏輯運算其實是布爾值到布爾值的運算,只不過在C當中,所有非零整數都理解為true,所有0都理解為false。所以4 2 == 1,其實是4是true,2也是true,與的結果是true,所以是1。而按位操作,4是0b0100, 2是0b0010,它們沒有重疊的二進位位,所以結果是4 2 == 0


就是因為 C 語言沒有嚴格意義上的 bool,表示 true 和 false 的時候語義含糊,任何數值其實都成了 bool。

如果把邏輯運算的操作數限定成 bool 類型,就非常清晰,不會有讓初學者迷惑的地方。

你截圖上的問題,

第一個問題其實是 和 || 的短路邏輯。假設說一個語句中出現了兩個 ,只要表達式計算出了 false,計算會被立刻終止,因為 false 任何值最終都是 false,|| 類似。

第二個問題,位與和邏輯與是完全不同的操作符,他們根本就不能互相替代,計算邏輯也不是位運算符的一部分功能。但是位與的結果在 C 裡面恰好可以是邏輯值,這就是導致看起來可用的原因。

(所以你可能會在 C 代碼裡面看到 if (a 1) 來判斷 a 的奇偶性,但這個寫法在 Java 或者 Swift 這樣有嚴格 bool 類型的裡面是錯的,因為位運算的結果不應該充當一個邏輯值。)

這兩個都是錯誤的問答。


: 兩個數字 位操作 AND。或者取某個變數的地址,或聲明引用。

對 bit:(0 x ) = 0; ( 1 x ) = x;

:兩個 bool 值的「並且」。( false x ) = false; (true x)= x;

|:兩個數字 位操作 OR。對 bit: ( 0 | x ) = x; ( 1 | x ) = 1;

||:兩個bool 值的「或」。( true || x ) = true; ( false || x ) = x;

----

a = !!a;

(a b) = !(!a || !b);

!(a b) = (!a || !b);

(a || b) = !(!a !b);

!(a || b) = (!a !b);

ps:你這本書扔了吧,說的什麼,不知所云。( 位操作和 bool 邏輯運算豈能混為一談?)


看了不少大神的回答,把這個問題總結一下,有問題務必請指出來。

1.|和最後算的結果是位數運算值(|和被稱為bitwise operator,位數運算符),也就是整數,在C語言里在只要不等於0就是真,所以有時候可以替換||和,程序也沒問題,但是一般這種替換靜態程序分析軟體(static code analyzer)會報錯,所以最好一開始就養成好的習慣。比如 if a&>10 b&<10,因為等同於11==1,和11==1最後的值一樣,雖然前者是位數運算算的是整數,後者是布爾運算算的是布爾運算的真值,這時候用代替也可以執行正常。

2.關於 if 4 6,值是true,因為4的二進位數是100,6的二進位數是110,第一位是00結果是0,第二位是01結果是0,第三位是11結果是1,所以最後結果的二進位值是100,十進位值是4,邏輯判斷非0也就是true。但是如果是用if 4 6算,那麼就直接算邏輯部分,1 (true)1(true),值是1,也是True(布爾運算值里true值是1)。所以雖然有時可以代替,但是兩個運算涉及的值不一樣。如果是if 4 2,那麼就會出問題,因為4是100, 2是010,它們沒有重疊的二進位位,所以結果是4 2 == 0,所以這時候 4 2==1,用和值就不一樣了。

3.感謝評論區提醒的和||短路求值的情況,我是這樣理解的,不知道對不對,不對還請指出。也就是問題中提到的第一點。比如 0 1==0,計算機是要算0和1共2個條件,而01==0,只要算到前一個值為假就結束,所以有時可以不用算第二個條件。同樣對於1 || 0==1,因為第一個條件已經可以決定結果,所以就跳過第二個條件,取真。

今天剛消化出來的,如有錯誤,務必指出。

-------分割線---------

回復@千里冰封

不知道為什麼,越來越不敢在知乎提問課本和專業書籍的細節問題,總有人問為啥不問老師不搜索,我只能說我目前是自學,而且即使之前在大學問老師,老師也不會有時間回答或者詳細解釋,另外國內搜索引擎噪音太多總是沒能找到最佳解釋的網頁,國外的總有內容看不懂。本來是先在Quaro 問,怕看不懂再在知乎問一遍,可發現對於學科細節問題,知乎的友好度比Quaro差了好多,導致很多問題都憋著不敢在知乎問,以前是從小學到大學問了老師就要先挨罵,現在在網上問個問題也總是遇到罵聲,感覺怪怪的。這個問題是因為書是中文的,不好到Quaro上直接掛出圖來問,而且好像搜索引擎無法搜布爾運算符(如果你能理解搜索引擎的基本演算法就知道無法用布爾運算算布爾運算符,不信可以試試),就想在知乎上可以問的詳細點,在Quaro 上問的泛一點。結果,果然又在知乎上挨罵了,同時在Quaro 上得到很多大神詳細的回復。當然還是很感激有大神可以答疑解惑(在這裡感謝@靈劍 大神,每次您的熱情回復都讓我有勇氣繼續提問,非常感激),只是自從自學以來發現國內社區讓人很沮喪的一面,如果不是Quaro對應的熱情洋溢的回答,我真的認為也許我該像@千里冰封 那樣舉報自己的問題拉低了知乎社區的智商水平了。

貼一個對應問題的Quaro 鏈接,只是為了證明自己提這類問題的正當性(在瀏覽器打開可見所有詳細回答 ):

What is difference between and ,| and || in C programming language?

https://www.quora.com/What-is-difference-between-and-%EF%BC%8C-and-in-C-programming-language?

srid=pCShshare=13433b87

關於我為什麼還要來知乎再問一遍:有部分問題的辭彙和句子比較晦澀難懂(比如上述問題的排名最高的回答有個計算機用語字典里查不到,後來找了很久才找到這個詞的解釋,如下圖所示,如果是難懂的句子可能有時就無能為力),怕錯過重點信息所以每個問題再來知乎問一遍,一般許多問題會再結合知乎和Quaro 以及其它資料把自己的理解綜述一遍作為這個問題的回答,也可以對後來者有所啟發,我想更多的資料才是搜索引擎和討論區存在的價值。


因為C在高級語言中比較奇葩,與其說C沒有boolean類型,不如說C很多時候就無所謂類型。以32位程序為例,一個32位的變數a既可以表示布爾值,也可以表示為整數,也可以表示為指針

例如在 if(a){}、ab 這類邏輯操作中,a會被當作布爾值,為0表示假,其他時候為真。並且在和||操作中有短路運算

而和|其實應該和+、-、*、/等歸到一起,這類運算將兩個32位的操作數視為整數,因此沒有短路運算。當然了,因為兩個整數、|計算出來的結果,在是不是等於0的問題上,剛好和、||一樣,因此題主的書中寫到「也不是不行」

至於為什麼C會這麼設計,就我理解很大程度上是C最初是針對彙編語言設計的高級語言,因此它免不了包含了彙編語言的很多特性,同時也很容易翻譯為彙編語言。作為C程序員,很多時候還得考慮你的代碼最後會被編譯成什麼樣

在這個問題中,假設a、b兩個變數被保存在寄存器ax和bx中,那麼if(ab){...}else{...}可能被翻譯為:

cmp ax,0 ;比較ax和0
je ELSE ;相等則跳轉至ELSE分支
cmp bx,0 ;比較bx和0
je ELSE ;相等則跳轉至ELSE分支
IF: ... ;IF分支
jmp END ;IF分支結束後跳轉至END分支
ELSE:... ;ELSE分支
END:... ;結束

而if(ab){...}else{...}則可能被翻譯為:

and ax,bx ;對ax和bx進行按位與操作
jz ELSE ;如果標記位為0,跳轉至ELSE分支
IF:... ;後邊邏輯同上
jmp END
ELSE:...
END:...

可以看出,兩種運算在彙編層面上是兩回事,而且很顯然和||有短路運算特性


一直覺得知乎作為高知交流平台,不應該總是出現百度一下就可以輕鬆解決的問題,但一看到大家對於簡單問題也答得這麼用心、答得如此深入本質、答到我自愧弗如!

隨即讓我想起愛因斯坦的一句話:「如果你不能簡單地解釋一樣東西,說明你沒真正地理解它。」對於一種事物、一個問題的解釋,問題本身的難易當然不能決定回答的層次水平,而解釋人、回答者卻可以。

所以說,把難或易的問題都解釋得通透明了,深入本質這才是知乎區別其他平台的亮點,而不是所問的問題有多高檔。


請看CSAPP 2.1.8和2.1.9節,並完成相關習題。

不過,,這是語言的基本知識啊。。。


上面有人胡扯。c裡面無bool,單寫因為是運算表達式確實要計算出結果,而結果只能是0或者大於0,這個結果當然可以作為條件判斷的真假。雙寫的話是邏輯表達式,按照離散數學的邏輯運算路子走,各種結合律等,當然這個有編譯器做詞法分析等,如果一個子表達式違反邏輯運算預期就不再計算後面表達式……


《深入理解計算機系統》2.1.8節和2.1.9節詳細講述了C語言中「位級運算」和「邏輯運算」的區別,強烈推薦題主入門之後看看這本經典。


位運算和邏輯運算的區別。


為什麼不百度?


推薦閱讀:

強人工智慧的產生是否離不開數理邏輯的支撐?
求幫助,Python閉包和返回函數問題?
如何紮實地學習Lisp?
具體的講,C#相比JAVA有哪些先進的地方?
計算機專業不學c語言是怎樣的存在?

TAG:程序員 | 編程語言 | 編程 | C編程語言 | CC |