C語言中文網 目錄
首頁 > 編程筆記 > C語言筆記 閱讀:2,762

原碼、反碼、補碼及位操作符,C語言位操作詳解

計算機中的所有數據均是以二進制形式存儲和處理的。所謂位操作就是直接把計算機中的二進制數進行操作,無須進行數據形式的轉換,故處理速度較快。

原碼、反碼和補碼

位(bit)是計算機中處理數據的最小單位,其取值只能是 0 或 1。

字節(Byte)是計算機處理數據的基本單位,通常系統中一個字節為 8 位。即:1 Byte=8 bit。

為便于演示,本節表示的原碼、反碼及補碼均默認為 8 位。

準確地說,數據在計算機中是以其補碼形式存儲和運算的。在介紹補碼之前,先了解原碼和反碼的概念。

正數的原碼、反碼、補碼均相同。

原碼:用最高位表示符號位,其余位表示數值位的編碼稱為原碼。其中,正數的符號位為 0,負數的符號位為 1。

負數的反碼:把原碼的符號位保持不變,數值位逐位取反,即可得原碼的反碼。

負數的補碼:在反碼的基礎上加 1 即得該原碼的補碼。

例如:
+11 的原碼為: 0000 1011
+11 的反碼為: 0000 1011
+11 的補碼為: 0000 1011

-7 的原碼為:1000 0111
-7 的反碼為:1111 1000
-7 的補碼為:1111 1001

注意,對補碼再求一次補碼操作就可得該補碼對應的原碼。

位操作符

語言中提供了 6 個基本的位操作符,如表 2 所示。

表 2 C語言運算符
運算符 功 能 運算規則
& 按位與 對應位均為 1 時,結果才為 1
| 按位或 兩位中只要有一位為 1,結果為 1。
只有兩位同時為 0 時,結果為才為 0。
^ 按位異或 兩位相異時,結果為 1;兩位相同時,結果為 0。
<< 左移 將運算數的各二進制位均左移若干位,高位丟棄(不包括 1),低位補 0,每左移一位,相當于該數乘以 2。
>> 右移 將運算數的各二進制位均右移若干位,正數補左補 0,負數左補 1,右邊移出的位丟棄。
~ 按位取反 0 變 1,1 變 0。

注意,計算機中位運算操作,均是以二進制補碼形式進行的。

按位與(&)

只有兩位同時為 1 時,結果才為 1;只要兩位中有一位為 0,則結果為 0。用式子表示為:

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

復合賦值運算符:&= 表示按位與后賦值。

例如,計算 20 和 9 按位與的結果,如下所示。


即:20&9=0。

應用一:使用 0x01 與一個數按位與,可獲取該數對應二進制數的最低位。
應用二:使用 0x00 與一個數按位與,可使該數低位的一個字節清零。

例如,9&0x1 可求得 9 對應二進制數 0000 1001 的最低位 1。

【例 1】分析以下程序的功能,并輸出其運行結果。
#include<stdio.h>
int main (void)
{
int n;
for(n=1;n<=20;n++)
  if (0==(n&0x1))
            printf("%d ",n);
    printf ("\n");
    return 0;
}
程序運行結果為:
2 4 6 8 10 12 14 16 18 20

程序分析:
n&0x1 的功能是取出 n 對應補碼二進制數的最低位(最右端位),如果該位為 0,則輸出。二進制數 bn-1bn-2bn-3…b2b1b0。對應的十進制數 N 的表達式為:

N=b0 X 20 + b1 X 21 + b2 X 22 + b3 X 23 + b4 X 24 + …

由于從上式中第二項開始的每一項都是偶數,故N是否偶數取決于 b0 是否偶數,故 b0 為 1 時是奇數,為 0 時是偶數。

按位或(丨)

只要兩位中有一位為 1,結果為 1;只有兩位同時為 0 時,結果才為 0。用式子表示為:

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

復合賦值運算符:|= 按位或后賦值。

例如,計算 20 和 9 按位或的結果,如下所示。


即: 20 | 9 = 29。

按位異或(^)

當兩位相同時,即同為 1 或同為 0 時,結果為 0;當兩位相異時,即其中一位為 1,另一位為 0 時,結果為 1。即相同為 0,相異為 1。用式子表示為:

0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

由此可得按位異或的 6 個性質或特點如下。
  1. a^0=a。即0與任意數按位異或都得該數本身。
  2. 1 與任意二進制位按位異或都得該位取反(0 變 1,1 變 0)。
  3. a^a=0。即任意數與自身按位異或都得0。
  4. a^b=b^a。即滿足交換律。
  5. (a^b)^c=a^(b^c)。即滿足結合律。
  6. a^b^b=a^(b^b)=a^0=a。

復合賦值運算符:^= 按位異或后賦值。

例如,計算 22 和 7 按位異或的結果,如下所示。


即:22^7=17。

【例 2】分析以下程序的功能。
#include<stdio.h>
int main (void)
{
    int a=3,b=5;
    a=a^b;
    b=a^b;
    a=a^b;
    printf("a=%d,b=%d\n",a,b);
    return 0;
}
運行結果:
a=5,b=3

程序分析:
本題是對按位異或的性質和特點的綜合運用,由于沒有使用中間變量,故在理解上存在一定的難度。

由于 a=a^b; 故:
b=a^b=a^b^b=a^(b^b)=a^0=a,即:b=3。
a=a^b=(a^b)^a=(b^a)^a=b^(a^a)=b^0=b,即:a=5。

故實現了 a 與 b 的交換。

左移(<<)

將運算數的各二進制位均左移若干位,高位丟棄(不包含 1),低位補 0。左移時舍棄的高位不包含 1,則每左移一位,相當于該數乘以 2。

復合賦值運算符: <<= 左移后賦值。

例如,計算 10 左移兩位的結果,如下所示。


丟棄左邊高位移出去的 0,低位補 0。

左移一位相當于該數乘以 2,本例中左移兩位,故相當于乘以 4。即:10<<2 = 10 X 2 X 2 = 40。

右移(>>)

將運算數的各二進制位全部右移若干位,正數左補 0,負數左補 1,右邊移出的位丟棄。

復合賦值運算符: >>= 右移后賦值。

例如,計算 70 右移兩位的結果,如下所示。


丟棄右邊移出去的所有位,由于該數為正數,左邊補 0。

右移一位相當于該數除以 2 取整,本例中右移兩位,故相當于除以 4 取整。即:70>>2=70/4 = 17。

按位取反(~)

0 變 1,1 變 0。用式子表示為:

~0 = 1
~1 = 0

應用:~a+1=-a 即對任意數按位取反后加 1,得該數的相反數。

例如,計算 10 按位取反的結果,如下所示:


由于計算機中位運算均是以補碼形式操作的,正數的補碼是其本身,負數的補碼為其反碼加 1。


所得顯然是負數的補碼,對補碼 1111 0101 再做一次求補操作,即可得該補碼對應的原碼。 求 1111 0101 補碼的過程如下所示。

反碼 1000 1010 --符號位 1 保持不變,數值位按位取反
補碼 1000 1011 --反碼加1
根據 (補碼)補碼=原碼
故補碼1111 0101對應的原碼為1000 1011=-11,即:~(10)D =~(0100 0110)B補= (1111 0101)B補=-11

由此可見,~10+1=-11+1=-10,即滿足 ~a+1=-a。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo