C語言中位操作用法

2021-08-04 15:00:52 字數 4775 閱讀 3400

一、前言

在對單處機進行程式設計的過程中,對位的操作是經常遇到的。c51對位的操控能力是非常強大的。從這一點上,就可以看出c不光具有高階語言的靈活性,又有低階語言貼近硬體的特點。這也是在各個領域中都可以看到c的重要原因。在這一節中將詳細講解c51中的位操作及其應用。
二、位運算子

c提供了幾種位操作符,如下表所示:

三、位操作運算

1.「按位與」運算子(&)

參加運算的兩個資料,按二進位進行「與」運算。原則是全1為1,有0為0,即:0&0=0; 0&1=0; 1&0=0; 1&1=1; 如下例:

a=5&3; //a=(0b 0101) & (0b 0011) =0b 0001 =1

那麼如果參加運算的兩個數為負數,又該如何算呢?會以其補碼形式表示的二進位制數來進行與運算。

a=-5&-3; //a=(0b 1011) & (0b1101) =0b 1001 =-7

在實際的應用中與操作經常被用於實現特定的功能:

1)清零

「按位與」通常被用來使變數中的某一位清零。如下例:

a=0xfe; //a=0b 11111110

a=a&0x55; //使變數a的第1位、第3位、第5位、第7位清零 a= 0b 01010100

2)檢測位

要知道乙個變數中某一位是『1』還是『0』,可以使用與操作來實現。

a=0xf5; //a=0b 11110101

result=a&0x08; //檢測a的第三位,result=0

3)保留變數的某一位

要遮蔽某乙個變數的其它位,而保留某些位,也可以使用與操作來實現。

a=0x55; //a=0b 01010101

a=a&0x0f; //將高四位清零,而保留低四位 a=0x05

參與或操作的兩個位,只要有乙個為『1』,則結果為『1』。即有『1』為『1』,全『0』為『0』。0|0=0; 0|1=1; 1|0=1; 1|1=1;例如:

a=0x30|0x0f; //a=(0b00110000)|(0b00001111)=(0b00111111)=0x3f

「按位或」運算最普遍的應用就是對乙個變數的某些位置『1』。如下例:

a=0x00; //a=0b 00000000

a=a|0x7f; //將a的低7位置為1,a=0x7f

異或運算子^又被稱為xor運算子。當參與運算的兩個位相同(『1』與『1』或『0』與『0』)時結果為『0』。不同時為『1』。即相同為0,不同為1。 0^0=0; 0^1=1; 1^0=1;1^1=0;例如:
a=0x55^0x3f; //a=(0b01010101)^(0b00111111)=(0b01101010)=0x6a

異或運算主要有以下幾種應用:
1)翻轉某一位:當乙個位與『1』作異或運算時結果就為此位翻轉後的值。如下例:

a=0x35; //a=0b00110101

a=a^0x0f; //a=0b00111010 a的低四位翻轉

關於異或的這一作用,有乙個典型的應用,即取浮點的相反數,具體的實現如下:

f=1.23; //f為浮點型變數 值為1.23

f=f*-1; //f乘以-1,實現取其相反數,要進行一次乘運算

f=1.23;

((unsigned char *)&f)[0]^=0x80; //將浮點數f的符號位進行翻轉實現取相反數

2)保留原值:當乙個位與『0』作異或運算時,結果就為此位的值。如下例:

a=0xff; //a=0b11111111

a=a^0x0f; //a=0b11110000 與0x0f作異或,高四位不變,低四位翻轉

3)交換兩個變數的值,而不用臨時變數,要交換兩個變數的值,傳統的方法都需要乙個臨時變數。實現如下:

void swap(unsigned char *pa,unsigned char *pb)

而使用異或的方法來實現,就可以不用臨時變數,如下:

void swap_xor(unsigned char *pa,unsigned char *pb)

從上例中可以看到異或運算在開發中是非常實用和神奇的。

與其它運算子不同,「取反」運算子為單目運算子,即它的運算元只有乙個。它的功能就是對運算元按位取反。也就是是『1』得『0』,是『0』得『1』。~1=0; ~0=1;如下例:

a=0xff;//a=0b11111111

a=~a;//a=0b00000000

1)對小於0的有符號整型變數取相反數

d=-1;//d為有符號整型變數,賦值為-1,記憶體表示為0b 1111111111111111

d=~d+1;//取d的相反數,d=1,記憶體表示0b 0000000000000001        

此例運用了負整型數在記憶體以補碼方式來儲存的這一原理來實現的。負數的補碼方式是這樣的:負數的絕對值的記憶體表示取反加1,就為此負數的記憶體表示。如-23如果為八位有符號整型數,則其絕對值23的記憶體表示為0b00010111,對其取反則為0b11101000,再加1為0b11101001,即為0xe9,與keil**結果是相吻合的。

2)增強可移植性

關於「增強可移植性」用以下例項來講解:假如在一種微控制器中unsigned char型別是八個位(1個位元組),那麼乙個此型別的變數a=0x67,對其最低位清零。則可以用以下方法:

a=0x67; //a=0b 0110 0111

a=a&0xfe; //a=0b 0110 0110

上面的程式似乎沒有什麼問題,使用0xfe這一因子就可以實現乙個unsigned char型的變數最低位清零。但如果在另一種微控制器中的unsigned char型別被定義為16個位(兩個位元組),那麼這種方法就會出錯,如下:

b=0x6767; //假設b為另一種微控制器中的unsigned char 型別變數,值為0b 0110 0111 0110 0111

b=b&0xfe; //如果此時因子仍為0xfe的話,則結果就為0b 0000 0000 0110 0110 即0x0066,而與0x6766不相吻合

上例中的問題就是因為不同環境中的資料型別差異所造成的,即程式的可移植性不好。對於這種情況可以採用如下方法來解決:

a=0x67; //a=0b 0110 0111

a=a&~1; //在不同的環境中~1將自動匹配運算因子,實現最後一位清零 a=0x66 其中~1為 0b 11111110

b=0x6767; //a=0b 0110 0111 0110 0111

b=a&~1; //~1=0b 1111 1111 1111 1110,b=0b 0110 0111 0110 0110 ,即0x6766

左移運算子用來將乙個數的各位全部向左移若干位。如:

a=a<<2

表示將a的各位左移2位,右邊補0。如果a=34(0x22或0b00100010),左移2位得0b10001000,即十進位制的136。高位在左移後溢位,不起作用。

從上例可以看到,a被左移2位後,由34變為了136,是原來的4倍。而如果左移1位,就為0b01000100,即十進位制的68,是原來的2倍,很顯然,左移n位,就等於乘以了2n。但一結論只適用於左移時被溢位的高位中不包含『1』的情況。比如:

a=64; //a=0b 0100 0000

a=a<<2; //a=0b 0000 0000

其實可以這樣來想,a為unsigned char型變數,值為64,左移2位後等於乘以了4,即64x4=256,而此種型別的變數在表達256時,就成為了0x00,產生了乙個進製,即溢位了乙個『1』。

在作乘以2n這種操作時,如果使用左移,將比用乘法快得多。因此在程式中適應的使用左移,可以提高程式的執行效率。

##6. 右移運算子

右移與左移相類似,只是位移的方向不同。如:

a=a>>1

表示將a的各位向右移動1位。與左移相對應的,左移一位就相當於除以2,右移n位,就相當於除以2n。在右移的過程中,要注意的乙個地方就是符號位問題。對於無符號數右移時左邊高位移和『0』。對於有符號數來說,如果原來符號位為『0』,則左邊高位為移入『0』,而如果符號位為『1』,則左邊移入『0』還是『1』就要看實際的編譯器了,移入『0』的稱為「邏輯右移」,移入『1』的稱為「算術右移」。keil中採用「算術右移」的方式來進行編譯。如下:

d=-32; //d為有符號整型變數,值為-32,記憶體表示為0b 11100000

d=d>>1;//右移一位 d為 0b 11110000 即-16,keil採用」算術邏輯」進行編譯

在對乙個變數進行了位操作中,要將其結果再賦給該變數,就可以使用位運算賦值運算子。位運算賦值運算子如下:&=, |=,^=,~=,<<=, >>= 例如:

a&=b相當於a=a&b,a>>=2相當於a>>=2。

如果參與運算的兩個資料的長度不同時,如a為char型,b為int型,則編譯器會將二者按右端補齊。如果a為正數,則會在左邊補滿『0』。若a為負數,左邊補滿『1』。如果a為無符號整型,則左邊會添滿『0』。

a=0x00; //a=0b 00000000

d=0xffff; //d=0b 11111111 11111111

d&=a; //a為無符號型,左邊添0,補齊為0b 00000000 00000000,d=0b 00000000 00000000

C語言中位操作

0 0 0 0 1 0 1 0 0 1 1 1 0 0 0 0 1 1 1 0 1 1 1 1 1.不改變其他位的值的狀況下,對某幾個位進行設值。先對需要設定的位用 操作符進行清零操作,然後用 操作符設值。比如我要改變 gpioa 的狀態,可以先對暫存器的值進行 清零操作 gpioa crl 0xf...

C語言中的位操作

目錄 1.前言 2.數值在計算機中的表示 3.位運算 4.位段 正文 1.前言 為了節省記憶體空間,在系統軟體中常將多個標誌狀態簡單地組合在一起,儲存到乙個位元組 或字 中。語言是為研製系統軟體而設計的,所以她提供了實現將標誌狀態從標誌位元組中分離出來的位運算功能。所謂位運算是指,按二進位制位進行的...

C 語言中的位操作

在微控制器或是工業控制中,位操作是很常見的,利用微控制器實現跑馬燈的例項就可以通過位操作來實現。c 語言中也能夠實現位操作。微操作是針對資料的二進位制補碼形式的操作,位操作符主要有 位運算子含義 與 或 非 異或 左移 右移 與等 或等 異或等 左移等 右移等 可以用下邊的類似程式實現二進位制的輸出...