C語言詳細(xì)講解位運(yùn)算符的使用
一、位運(yùn)算符分析
C語言中的位運(yùn)算符
位運(yùn)算符直接對 bit 位進(jìn)行操作,其效率最高。
& | 按位與 |
| | 按位或 |
^ | 按位異或 |
~ | 取反 |
<< | 左移 |
>> | 右移 |
左移和右移注意點(diǎn)
左操作數(shù)必須為整數(shù)類型
- char 和 short 被隱式轉(zhuǎn)換為 int 后進(jìn)行移位操作
右操作數(shù)的范圍必須為:[0,31]
左移運(yùn)算符<< 將運(yùn)算數(shù)的二進(jìn)制位左移
- 規(guī)則:高位丟棄,低位補(bǔ)0
右移運(yùn)算符>> 把運(yùn)算數(shù)的二進(jìn)制位右移
- 規(guī)則︰高位補(bǔ)符號(hào)位,低位丟棄
下面一段代碼:
#include <stdio.h> int main() { printf("%d\n", 3 << 2); printf("%d\n", 3 >> 1); printf("%d\n", -1 >> 1); printf("%d\n", 0x01 << 2 + 3); printf("%d\n", 3 << -1); // oops! return 0; }
下面為輸出結(jié)果:
注意四則運(yùn)算優(yōu)先級(jí)大于位運(yùn)算,所以 0x01 << 2 + 3 的結(jié)果是 32。 還有就是右操作數(shù)的范圍必須為:[0,31],如果不在這個(gè)范圍內(nèi),程序的輸出結(jié)果由不同類型的編譯器所決定,結(jié)果將不確定,就像本代碼 3 << -1 一樣。
二、小貼士
防錯(cuò)準(zhǔn)則:
- 避免位運(yùn)算符,邏輯運(yùn)算符和數(shù)學(xué)運(yùn)算符同時(shí)出現(xiàn)在一個(gè)表達(dá)式中
- 當(dāng)位運(yùn)算符,邏輯運(yùn)算符和數(shù)學(xué)運(yùn)算符需要同時(shí)參與運(yùn)算時(shí),盡量使用括號(hào) ( ) 來表達(dá)計(jì)算次序
小技巧:
- 左移 n 位相當(dāng)于乘以 2 的 n 次方,但效率比數(shù)學(xué)運(yùn)算符高
- 右移 n 位相當(dāng)于除以 2 的 n 次方,但效率比數(shù)學(xué)運(yùn)算符高
下面看一段交換兩個(gè)整型變量值的代碼:
#include <stdio.h> #define SWAP1(a,b) \ { \ int t = a; \ a = b; \ b = t; \ } #define SWAP2(a,b) \ { \ a = a + b; \ b = a - b; \ a = a - b; \ } #define SWAP3(a,b) \ { \ a = a ^ b; \ b = a ^ b; \ a = a ^ b; \ } int main() { int a = 1; int b = 2; //printf("a = %d\n", a); //printf("b = %d\n", b); SWAP1(a,b); printf("a = %d\n", a); printf("b = %d\n\n", b); a = 1; b = 2; SWAP2(a,b); printf("a = %d\n", a); printf("b = %d\n\n", b); a = 1; b = 2; SWAP3(a,b); printf("a = %d\n", a); printf("b = %d\n\n", b); return 0; }
第一種方法需要引入第三方變量,第二種方法可能會(huì)導(dǎo)致越界問題,第三種的方法效率較高,且不用引入第三方變量。
注意第三種方法:執(zhí)行 a = a ^ b; 后,b = a ^ b; 就相當(dāng)于 b = a ^ b ^ b; 先計(jì)算后面的,就是 b = a ^ 0,結(jié)果就是 b = a;再執(zhí)行a = a ^ b;相當(dāng)于 a = a ^ b ^ b,即 a = a ^ b ^ a,顯然結(jié)果是 b。
小知識(shí):
A 異或 0 等于 A ,A 異或 1 等于 非A。
三、位運(yùn)算與邏輯運(yùn)算
位運(yùn)算與邏輯運(yùn)算不同:
- 位運(yùn)算沒有短路規(guī)則,每個(gè)操作數(shù)都參與運(yùn)算
- 位運(yùn)算的結(jié)果為整數(shù),而不是 0 或 1
- 位運(yùn)算優(yōu)先級(jí)高于邏輯運(yùn)算優(yōu)先級(jí)
下面再來看一個(gè)混淆改變的判斷條件:
#include <stdio.h> int main() { int i = 0; int j = 0; int k = 0; if( ++i | ++j & ++k ) { printf("Run here...\n"); } printf("i = %d, j = %d, k = %d\n\n", i, j, k); i = 0; j = 0; k = 0; if( ++i || ++j && ++k ) { printf("Run here...\n"); } printf("i = %d, j = %d, k = %d\n\n", i, j, k); return 0; }
下面為輸出結(jié)果:
可以看到,如果錯(cuò)把++i || ++j && ++k 寫成++i | ++j & ++k,雖然都能運(yùn)行,但是其中的執(zhí)行細(xì)節(jié)不一樣,在實(shí)際工程中可能會(huì)出現(xiàn) bug,而且還不好排查。
四、小結(jié)
- 位運(yùn)算符只能用于整數(shù)類型
- 左移和右移運(yùn)算符的右操作數(shù)范圍必須為 [0,31]
- 位運(yùn)算沒有短路規(guī)則,所有操作數(shù)均會(huì)求值
- 位運(yùn)算的效率高于四則運(yùn)算和邏輯運(yùn)算
- 運(yùn)算優(yōu)先級(jí):四則運(yùn)算 > 位運(yùn)算 > 邏輯運(yùn)算
到此這篇關(guān)于C語言詳細(xì)講解位運(yùn)算符的使用的文章就介紹到這了,更多相關(guān)C語言 位運(yùn)算符內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言求Fibonacci斐波那契數(shù)列通項(xiàng)問題的解法總結(jié)
斐波那契數(shù)列相關(guān)問題是考研和ACM中常見的算法題目,這里特地為大家整理了C語言求Fibonacci斐波那契數(shù)列通項(xiàng)問題的解法總結(jié),需要的朋友可以參考下2016-06-06使用Qt實(shí)現(xiàn)監(jiān)聽網(wǎng)頁是否響應(yīng)并導(dǎo)出Excel表
Qt導(dǎo)出數(shù)據(jù)到excel,方法有很多,下面這篇文章主要給大家介紹了關(guān)于使用Qt實(shí)現(xiàn)監(jiān)聽網(wǎng)頁是否響應(yīng)并導(dǎo)出Excel表的相關(guān)資料,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11C++ opencv ffmpeg圖片序列化實(shí)現(xiàn)代碼解析
這篇文章主要介紹了C++ opencv ffmpeg圖片序列化實(shí)現(xiàn)代碼解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08