C語(yǔ)言各種符號(hào)的使用介紹下篇
1、按位運(yùn)算符
1.1 按位或( | )和按位與( & )
上期我們講到過(guò)邏輯或和邏輯與,他們得到的結(jié)果是真假值,但我們一定要區(qū)分清楚,按位運(yùn)算符 "|" 和 "&" 與邏輯運(yùn)算符 "||" "&&" 是完全兩個(gè)概念。
按位,簡(jiǎn)明之意,按數(shù)值二進(jìn)制位來(lái)進(jìn)行運(yùn)算,都是在數(shù)據(jù)補(bǔ)碼的基礎(chǔ)上進(jìn)行。
按位或 "|" :兩個(gè)數(shù)值的二進(jìn)制補(bǔ)碼對(duì)應(yīng)位進(jìn)行運(yùn)算,對(duì)應(yīng)位有 1 則為 1 ,否則為 0。
按位與 "&":兩個(gè)數(shù)值的二進(jìn)制補(bǔ)碼對(duì)應(yīng)位進(jìn)行運(yùn)算,對(duì)應(yīng)位都為 1 則為 1, 否則為 0。
這里我們舉例說(shuō)明:
1 | 2 :
1 的二進(jìn)制補(bǔ)碼:0000 0000 ... 0000 0001
2 的二進(jìn)制補(bǔ)碼:0000 0000 ... 0000 0010
------按位或結(jié)果: 0000 0000... 0000 0011 -> 對(duì)應(yīng)十進(jìn)制:3
1 & 2:
1 的二進(jìn)制補(bǔ)碼:0000 0000 ... 0000 0001
2 的二進(jìn)制補(bǔ)碼:0000 0000 ... 0000 0010
------按位與結(jié)果: 0000 0000... 0000 0000 -> 對(duì)應(yīng)十進(jìn)制:0
其實(shí)有很多大學(xué)老師或者是書(shū)上都有可能把按位或,按位與,以及后面我們要講的按位異或,他們會(huì)把每位二進(jìn)制運(yùn)算后的結(jié)果稱為真或者假,其實(shí)這樣的說(shuō)法是不夠嚴(yán)謹(jǐn)?shù)?,真假是邏輯判斷,而按位運(yùn)算得到的結(jié)果是數(shù)值,而且在C語(yǔ)言中0表示假,非0為真,所以我是不推薦這種說(shuō)法。
1.2 按位異或( ^ )
按位或 "^" :兩個(gè)數(shù)值的二進(jìn)制補(bǔ)碼對(duì)應(yīng)位進(jìn)行運(yùn)算,相同為 0 , 不同為 1。
這里我們舉例說(shuō)明:
1 ^3:
1 的二進(jìn)制補(bǔ)碼:0000 0000 ... 0000 0001
3 的二進(jìn)制補(bǔ)碼:0000 0000 ... 0000 0011
---按位異或結(jié)果: 0000 0000... 0000 0010 -> 對(duì)應(yīng)十進(jìn)制:2
5 ^0:
5 的二進(jìn)制補(bǔ)碼:0000 0000 ... 0000 0101
0 的二進(jìn)制補(bǔ)碼:0000 0000 ... 0000 0000
---按位異或結(jié)果: 0000 0000... 0000 0101 -> 對(duì)應(yīng)十進(jìn)制:5
結(jié)論:任何數(shù)異或0都等于它本身
這里有一道筆試題:不創(chuàng)建臨時(shí)變量,實(shí)現(xiàn)兩個(gè)數(shù)的交換。
//很多小伙伴直接想出來(lái)的做法: int main() { int a = 10; int b = 20; printf("a = %d, b = %d\n", a, b); a = a + b; b = a - b; a = a - b; printf("a = %d, b = %d\n", a, b); return 0; }
但是我們仔細(xì)研究下這段代碼,他有沒(méi)有什么隱藏的問(wèn)題呢?
一個(gè)整型,占四個(gè)字節(jié),也就是 32 個(gè)比特位,這里進(jìn)行加法運(yùn)算,就會(huì)產(chǎn)生進(jìn)位,萬(wàn)一我們是兩個(gè)很大的數(shù)相加呢?他們的和超過(guò)了整型最大存儲(chǔ)范圍,那么在計(jì)算機(jī)里面就會(huì)發(fā)生截?cái)?!為了避免發(fā)生這種現(xiàn)象,我們可以采取異或的方法來(lái)實(shí)現(xiàn)這道題:
最后還有一個(gè)很簡(jiǎn)單的按位取反操作符:~
用途:對(duì)一個(gè)數(shù)的二進(jìn)制按位取反(包括它的符號(hào)位)
注意:以上的位運(yùn)算符,他們的操作數(shù)必須是整數(shù)!
1.3 一個(gè)關(guān)于整型提升的問(wèn)題
有這樣一串代碼,問(wèn):為什么一個(gè)char類(lèi)型大小可以求出來(lái)是4字節(jié)?
無(wú)論任何位運(yùn)算符,都是要計(jì)算機(jī)進(jìn)行計(jì)算的,而計(jì)算機(jī)中CPU具有運(yùn)算能力,但計(jì)算的數(shù)據(jù)都是放在內(nèi)存中的。所以,做任何運(yùn)算,都必須將數(shù)據(jù)從內(nèi)存拿到CPU的寄存器中。而寄存器默認(rèn)的操作數(shù)寬度是32位,可是,char類(lèi)型數(shù)據(jù)只有1個(gè)字節(jié),也就是8位,不滿足32位怎么辦,這就需要整型提升了?。ㄔ敿?xì)整型提升大家可以查閱資料哦)
如果是一個(gè)有符號(hào)數(shù)的話:高位補(bǔ)符號(hào)位
如果是一個(gè)無(wú)符號(hào)數(shù)的話:高位補(bǔ)0
2、移位操作符
2.1 左移<< 右移>>操作符
<< 左移運(yùn)算符是一個(gè)雙目運(yùn)算符,功能是把左邊的運(yùn)算數(shù)的各個(gè)二進(jìn)制位向左移動(dòng)指定位數(shù)。
>> 右移運(yùn)算符是一個(gè)雙目運(yùn)算符,功能是把右邊的運(yùn)算數(shù)的各個(gè)二進(jìn)制位向右移動(dòng)指定位數(shù)。
注意:
<< 左移:最低位丟棄,最高位補(bǔ)零
>> 右移:
- 無(wú)符號(hào)數(shù):最低位丟棄,最高位補(bǔ)零 [邏輯右移]
- 有符號(hào)數(shù):最低位丟棄,最高位補(bǔ)符號(hào)位 [算數(shù)右移]
以上在補(bǔ)碼中進(jìn)行運(yùn)算
警告:移位運(yùn)算符,請(qǐng)不要移動(dòng)負(fù)數(shù)位,這是標(biāo)準(zhǔn)未定義的!
左移我們好說(shuō),主要是右移我們需要細(xì)講一下:
明顯看到,這是在無(wú)符號(hào)數(shù)下進(jìn)行右移,第一個(gè)小伙伴都不會(huì)感到驚訝, 可是第二個(gè)就有點(diǎn)不理解了,我們來(lái)解釋下:
這里有一個(gè)問(wèn)題,當(dāng) -1 準(zhǔn)備放入變量 b 的時(shí)候我們需要看-1的類(lèi)型嗎?
答案是不需要!內(nèi)存中放的都是二進(jìn)制補(bǔ)碼,本質(zhì)上是把 -1 的補(bǔ)碼放入變量 b 當(dāng)中,第二,右移操作符屬于計(jì)算,需要在CPU中進(jìn)行,所以需要先把內(nèi)存中 -1 的補(bǔ)碼拿到CPU寄存器中運(yùn)算,按照我們的規(guī)則,右移中,無(wú)符號(hào)數(shù)低位丟棄高位補(bǔ)零,所以 -1 右移完成之后就變成了 0111 1111 ... 1111 1111,接著我們以 %d 有符號(hào)整型打印,就會(huì)把他當(dāng)作有符號(hào)數(shù)看待,最高位是 0 所以被認(rèn)為是正數(shù),轉(zhuǎn)化成十進(jìn)制也就是如上打印的值。
第二個(gè)我們來(lái)看下有符號(hào)數(shù)右移:
這個(gè)相信大家就很好理解了,第一個(gè)高位補(bǔ)符號(hào)位也就是補(bǔ) 0,低位丟棄,所以結(jié)果是 0,第二個(gè)高位補(bǔ)符號(hào)位也就是補(bǔ) 1,低位丟棄,值仍然不變,還是 -1。
注意:a>>1 并不會(huì)改變 a 變量的值,就好比如 a + 1。這樣寫(xiě)才會(huì)改變:a = a >> 1;
2.2 習(xí)題練習(xí)
學(xué)完了上期的邏輯操作符,和本期的移位操作符,我們來(lái)練練手:
請(qǐng)你設(shè)計(jì)一個(gè)宏可以指定數(shù)據(jù)第幾個(gè)比特位更改為 1 ,并設(shè)計(jì)一個(gè)函數(shù)將各個(gè)比特位打印出來(lái)。
//參考 #define SETBIT(a, num) ((a) |= (1 << (num - 1)) ) void PrintBit(int a) { int num = 31; while (num >= 0) { if ((a & (1 << num))) printf("1"); else printf("0"); --num; } printf("\n"); } int main() { int a = 0; SETBIT(a, 5); PrintBit(a); return 0; }
3、++和--的操作
3.1 基本操作
其實(shí)這節(jié)知識(shí)點(diǎn)理解起來(lái)是很簡(jiǎn)單的,只不過(guò)總有些學(xué)校喜歡出一些很拉跨的題目:
int i = 3; 問(wèn):(++i) + (++i) + (++i) 的值是多少?
我的建議是,看到這類(lèi)題,直接空著,你也可以在下面添一句,“ 你禮貌嗎?”
這種表達(dá)式,在任何編譯器下算出來(lái)的結(jié)果是不一樣的!
對(duì)于這種問(wèn)題沒(méi)必要去爭(zhēng)論誰(shuí)對(duì)誰(shuí)錯(cuò), 如果有人想跟你杠的話,那么你直接告訴他,你真的超級(jí)高水平。
好了,言歸正傳,我們來(lái)說(shuō)一下 ++ 和 -- 的基本理解:
- 前置++ -- :先自增(減),再使用
- 后置++ -- : 先使用,再自增(減) 如果沒(méi)有變量接收,那么直接自增。
例子:
基本使用就是這么多,接下來(lái)我們從匯編角度來(lái)深度理解一下:
3.2 從匯編角度深入理解a++
既然我們知道,后置++ 是先使用后++,如果我們單純的就 ++ 一下呢,他這個(gè)值被使用到了哪里去了呢?
int main() { int a = 0xDD; int b = a++; //有b接收,那么a的先使用是將a的值(內(nèi)容),放到b中 int c = 0xEE; c++; //沒(méi)有接收方,那么"先使用",如何理解? return 0; }
vs2019編譯器反匯編:
結(jié)論:后置++ 完整的含義是先使用,在自增,如果沒(méi)有變量接收,那么直接自增。
注意:在不同的編譯器可能處理過(guò)程不同,不過(guò)這是一個(gè)基本的研究過(guò)程,比單純的理論學(xué)習(xí)更嚴(yán)謹(jǐn)。
到此這篇關(guān)于C語(yǔ)言各種符號(hào)的使用介紹下篇的文章就介紹到這了,更多相關(guān)C語(yǔ)言符號(hào)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C語(yǔ)言各種符號(hào)的使用介紹上篇
- C語(yǔ)言詳細(xì)解析有符號(hào)數(shù)與無(wú)符號(hào)數(shù)的表示
- C語(yǔ)言詳細(xì)講解注釋符號(hào)的使用
- C語(yǔ)言特殊符號(hào)的補(bǔ)充理解
- 關(guān)于C語(yǔ)言中弱符號(hào)與弱引用的實(shí)際應(yīng)用問(wèn)題
- C語(yǔ)言中無(wú)符號(hào)與有符號(hào)及相加問(wèn)題
- C語(yǔ)言中無(wú)符號(hào)數(shù)和有符號(hào)數(shù)之間的運(yùn)算
- 舉例講解C語(yǔ)言鏈接器的符號(hào)解析機(jī)制
- 詳解C語(yǔ)言中的符號(hào)常量、變量與算術(shù)表達(dá)式
相關(guān)文章
Qt實(shí)現(xiàn)簡(jiǎn)單TCP服務(wù)器
這篇文章主要為大家詳細(xì)介紹了Qt實(shí)現(xiàn)簡(jiǎn)單TCP服務(wù)器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Opencv2.4.9函數(shù)HoughLinesP分析
這篇文章主要為大家詳細(xì)介紹了Opencv2.4.9函數(shù)HoughLinesP,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01Visual Studio 如何創(chuàng)建C/C++項(xiàng)目問(wèn)題
這篇文章主要介紹了Visual Studio 如何創(chuàng)建C/C++項(xiàng)目問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02如何判斷一個(gè)數(shù)是否為2的冪次方?若是,并判斷出來(lái)是多少次方?
本篇文章是對(duì)如何判斷一個(gè)數(shù)是否為2的冪次方?若是,并判斷出來(lái)是多少次方的實(shí)現(xiàn)方法,進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C++?STL中五個(gè)常用算法使用教程及實(shí)例講解
本文主要介紹了C++?STL算法中常見(jiàn)的五個(gè)算法的使用教程并附上了案例詳解,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-11-11C語(yǔ)言中g(shù)etchar(?)?函數(shù)使用詳解
getchar()?字符輸入函數(shù),沒(méi)有參數(shù),從輸入緩沖區(qū)里面讀取一個(gè)字,需要注意一次只能讀取一個(gè)字符,這篇文章主要介紹了C語(yǔ)言中g(shù)etchar函數(shù)使用詳解,需要的朋友可以參考下2022-12-12C語(yǔ)言實(shí)現(xiàn)文件操作實(shí)例(簡(jiǎn)單圖示講解)
與普通文件載體不同,文件是以硬盤(pán)為載體存儲(chǔ)在計(jì)算機(jī)上的信息集合,文件可以是文本文檔、圖片、程序等等,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言實(shí)現(xiàn)文件操作實(shí)例的相關(guān)資料,需要的朋友可以參考下2023-02-02