1. 程式人生 > >C語言學習筆記11--位運算

C語言學習筆記11--位運算

位運算概念

位運算是指按二進位制位進行的運算。因為在系統軟體中,常要處理二進位制位的問題。

例如:將一個儲存單元中的各二進位制位左移或右移一位,兩個數按位相加等。

c語言提供位運算的功能,與其他高階語言(如PASCAL)相比,具有很大的優越性。

位運算子和位運算

位運算子和位運算

(1)位運算子中除~以外,均為二目(元)運算子,即要求兩側各有一個運算量。

(2)運算量只能是整型或字元型的資料,不能為實型資料(浮點型)

“按位與”運算子(&)

含義:參加運算的兩個資料,按二進位制位進行“與”運算。

如果兩個相應的二進位制位都為1,則該位的結果值為1;否則為0。

例如:

0&0 = 0,0&1 = 0,

1&0 = 0,1&1 = 1

注意:

3&5並不等於8, 應該是按位與運算:

位運算子和位運算

如果參加&運算的是負數(如-3&-5), 則要

以補碼形式表示為二進位制數,然後再按位進行“與”運算。

按位與運算的用途

一、 清零

若想對一個儲存單元清零,即使其全部二進位制位為0,只要找一個二進位制數,其中各個位符合以下條件:原來的數中為1的位,新數中相應位為0。然後使二者進行&運算,即可達到清零目的。

例如:要求將二進位制數11100101的第2位清零

        1 1 1 0 0 1 0 1

  &   1 1 1 1 1 0 1 1

————————————

       1  1 1 0 0 0 0 1

二、取一個數中某些指定位

例如:我們需要對一個字型資料取出其低8位的值時,我們可以這麼做。

“按位或”運算子(|)

兩個相應的二進位制位中只要有一個為1,該位的結果值為1。

即:

0|0=0,0|1=1,

1|0=1,1|1=1

例如:

例:大小寫轉化

#include <stdio.h>
#include <conio.h>

void main()
{
      char ch, temp;

      printf("請輸入一個字母: \n");
      ch = getchar();
      temp = getchar();

      while( !(ch>'A' && ch<'z') || (ch > 'Z' && ch < 'a') )
      {
           printf("輸入有誤, 請重新輸入一個字母: \n");
           ch = getchar();
      }
      if( ch & 32 )  
      {
            ch = ch & 223;  // 使第五位為0,變大寫
      }
      else
      {
            ch = ch | 255;  // 使第五位為1,變小寫
      }

      putchar(ch);

      printf("\n");
}

因為回車了一下,回車也是一個字元,所以用getchar從輸入流中接收了回車符。所以用temp = getchar();這句接收下一。要不就出現兩句

這裡有專門的清除快取的函式。可以百度一下。

“異或”運算子(^)

異或運算子^也稱XOR運算子。

它的規則是:

若參加運算的兩個二進位制位同號則結果為0

(假),異號則結果為1(真)

即: 0^0=0,0^1=1,1^0=1, 1^1=0

例如:

異或運算子

^運算子應用

一、使特定位翻轉

設有01111010,想使其低4位翻轉,即1變為0,0變為1。可以將它與00001111進行^運算,即:

異或運算子使指定為翻轉

二、與0相^,保留原值

例如:

異或運算子的應用

因為原數中的1與0進行^運算得1,0^0得0,故保留原數。

三、交換兩個值,不用臨時變數

!這玩意新鮮!

例如:a=3,b=4,現在想將a、b變數的值交換位置,我們傳統的做法是定義多一個temp變數,而現在temp去度蜜月了,怎麼辦?

我們可以這樣做:

a=a^b;

b=b^a;

a=a^b;  

這種方法也常應用於加密演算法。

XOR異或

“取反”運算子(~)

~是一個單目(元)運算子,用來對一個二進位制數按位取反,即將0變1,將1變0。

例如,~025是對八進位制數25(即二進位制數00010101)按位求反。

例如:

“取反”運算子

左移運算子(<<)

左移運算子是用來將一個數的各二進位制 位全部左移若干位。

例如:a =<< 2 將a的二進位制數左移2位,右邊補0。

若a=15,即二進位制數00001111,左移2位得00111100,(十進位制數60)

若高位左移後溢位,捨棄。

左移1位相當於該數乘以2,左移2位相當於該數乘以4,15<<2=60,即乘了4。

但此結論只適用於該數左移時被溢位捨棄的高位中不包含1的情況。

假設以一個位元組(8位)存一個整數,若a為無符號整型變數,則a=64時,左移一位時溢位的是0,而左移2位時,溢位的高位中包含1。

右移運算子(>>)

右移運算子是a>>2表示將a的各二進位制位右移2位,移到右端的低位被捨棄,對無符號數,高位補0。

例如:a=017時: a的值用二進位制形式表示為00001111, 捨棄低2位11,得到 a >> 2 == 00000011

右移一位相當於除以2

右移n位相當於除以2^n

在右移時,需要注意符號位問題:

對無符號數,右移時左邊高位移入0;

對於有符號的值,如果原來符號位為0(該數為正),則左邊也是移入0。

如果符號位原來為1(即負數), 則左邊移入0還是1,要取決於所用的計算機系統。有的系統移入0,有的系統移入1。

移入0的稱為“邏輯右移”, 即簡單右移;移入1的稱為“算術右移”。

例:a的值是十進位制數 -2:

a == 1111 1110(用二進位制形式表示)

無符號數:a>>1: 0111 1111 (邏輯右移時)

有符號數:a>>1: 1111 1111 (算術右移時)

位運算賦值運算子

位運算子與賦值運算子可以組成複合賦值運算子。

例如: &=, |=, >>=, <<=, ∧=

a & = b 相當於 a = a & b

a << =2 相當於 a = a << 2

位運算舉例

題目:取一個char a從右端開始的2~5位。

① 先使a右移2位:a >> 2

目的是使要取出的那幾位移到最右端,圖示:

② 設定一個低4位全為1,其餘全為0的數。

~ ( ~ 0 << 4 )

③ 將上面①、②進行&運算。

(a >> 4) & ~ ( ~ 0 << 4 )

題目:要求將a進行右迴圈移位

迴圈移位

位段

資訊的存取一般以位元組為單位。實際上,有時儲存一個資訊不必用一個或多個位元組。

例如,“真”或“假”用0或1表示,只需1位即可。

在計算機用於過程控制、引數檢測或資料通訊領域時,控制資訊往往只佔一個位元組中的一個或幾個二進位制位,常常在一個位元組中放幾個資訊。

C語言允許在一個結構體中以位為單位來指定其成員所佔記憶體長度,這種以位為單位的成員稱為“位段”或稱“位域” ( bit field) 。利用位段能夠用較少的位數儲存資料。

struct  packed-data

unsigned  a:2;

unsigned b:6;

unsigned c:4;

unsigned d:4;

int i;

data

關於位段的定義和引用的說明

(1) 位段成員的型別必須指定為unsigned或int型別。

(2) 若某一位段要從另一個字開始存放,可用以下形式定義:

unsigned  a:1;

unsignedb:2;一個儲存單元

unsigned:0;

unsigned c:3;另一儲存單元

a、b、c應連續存放在一個儲存單元中,由於用了長度為0的位段,其作用是使下一個位段從下一個儲存單元開始存放。因此,只將a、b儲存在一個儲存單元中,c另存在下一個單元(“儲存單元”可能是一個位元組,也可能是2個位元組,視不同的編譯系統而異)。  

(3) 一個位段必須儲存在同一儲存單元中,不能跨兩個單元。如果第一個單元空間不能容納下一個位段,則該空間不用,而從下一個單元起存放該位段。

(4) 可以定義無名位段。

(5) 位段的長度不能大於儲存單元的長度,也不能定義位段陣列。

(6) 位段可以用整型格式符輸出。

(7) 位段可以在數值表示式中引用,它會被系統自動地轉換成整型數。