這篇部落客要介紹移位操作符與位操作符,在介紹這兩個操作符之前,先簡要講一下了解這兩個操作符需要的基礎知識——也就是二進制和原反補碼!
1.進制
進制是人為規定的一種進位方法,有很多種。比如,我們日常使用的數字即為十進制。十進制逢十進一,所有數字均由0-9組成。八進制逢八進一,所有數字均由0-7組成。二進制逢二進一,所有數字均由0、1組成。十六進制逢十六進一,所有數字由0-9,a-f組成。
在日常生活中也有很多進制的例子,例如星期,逢七進一,七進制;月份逢十二進一,十二進制;小時數,逢二十四進一,二十四進制。
而計算機是一個二進制系統,資料在計算機中以二進制的形式儲存。
2.整數的二進制表示
整數的二進制表示有三種,分别為原碼、補碼與反碼。正整數的原碼、補碼與反碼相同,而負整數的原碼、補碼與反碼是需要計算的。
整數在記憶體中一般以int類型存儲,int類型資料在記憶體中占四個位元組,32個比特位,即32個二進制位。
原碼是根據整數直接寫出的序列。值得注意的是,二進制序列的最高位是符号位,0代表是正數,1代表是負數。
例如:7。
7的原碼很簡單可以寫出:00000000 00000000 00000000 00000111

由于7為正整數,7的反碼、補碼與原碼相同。
例如:-7
由于-7為負數,是以-7二進制序列的符号位為1,即二進制序列的最高位為1。
是以,-7的原碼為:10000000 00000000 00000000 00000111
負數的補碼與反碼是需要計算的。
反碼:原碼的符号位不變,其他位按位取反即為反碼。
按位取反:每一個二進制位,原值為0,則改為1;原值為1,則改為0。
是以,-7的反碼:11111111 11111111 11111111 11111000
補碼:反碼加1即為補碼。
是以,-7的補碼:11111111 11111111 11111111 11111001
而整數在記憶體中是以補碼存儲的!!!
至此,基礎的小知識就說完啦!
3.移位操作符
移位操作符移的就是我們上文所講的二進制位!
移位操作符分為(<<)左移操作符和(>>)右移操作符。
注意:1.移位操作符的操作對象隻能為整數!
2.對于移位操作符,不要移動負數位(eg. int b=a>>-1),這個是标準未定義的,不同的編譯器下可能會産生不同的結果。
1.左移操作符
左移操作符:左邊丢棄,右邊補0(操作對象為在記憶體中存儲的補碼)。
例如,
int main()
{
int a = 7;
int b = a << 1;
printf("a = %d\n", a);
printf("b = %d\n", b);
return 0;
}
a左移1位指派給b,即下圖:
是以,代碼輸出結果為:
a左移一位後,a本身不會發生變化,隻會将左移一位後所得的值指派給b。
左移之後,之前的二進制碼均高了一位。是以,<<1其實有乘二的效果!
但它與乘2不同的是:<<1不會出現溢出現象,而某一個數字直接乘2所得的值可能會超過int型的範圍,産生溢出現象!
2.右移操作符
右移操作符有兩種移位規則,分别為邏輯移位與算術移位。
邏輯移位:左邊用0填充,右邊丢棄。
算術移位:左邊用該原值的符号位填充,右邊丢棄。
通常編譯器中采用的是算術移位!
右移一位相當于将這個數除以2!
是以,-7右移一位後補碼為:11111111 11111111 11111111 11111100
補碼減1後得反碼,即:11111111 11111111 11111111 11111011
除符号位按位取反得原碼,即:10000000 00000000 00000000 00000100
是以,-7右移一位後得-4。
代碼及輸出結果為:
同樣,a右移一位後,a本身不會發生變化,隻會将右移一位後所得的值指派給b。
4.位操作符
位操作符中的位同樣為二進制位!同時,位操作符操作數必須為整數!
位操作符有以下三種:
&:按位與
|:按位或
^:按位異或
1.按位與&
兩數的補碼對應二進制位均為1時,為1;有0時,則為0。
2.按位或
兩數的補碼對應二進制位均為0時,為0;有1時,則為1。
3.按位異或
兩數的補碼對應二進制位相同為0,相異為1。
按位異或有如下特點:
1. a^a=0;
2. 0^a=a;
3.按位異或運算支援交換律。例如:3^3^4=3^4^3=4。
4.按位異或應用
下面說明了按位異或的兩個基本小應用。
1.翻轉特定的二進制位
例如:
若想将a的第二位與第四位翻轉,可以将a與00001010(前三個位元組省略了)進行按位異或。
2.在不使用臨時變量的情況下,交換兩個變量的值。
例如:
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
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;
}
a首先被指派為3^5,b=a^b=3^5^5=3,a=a^3=3^5^3=5,至此完成兩個變量值的交換。
5.位操作符與移位操作符的幾個應用
1.統計二進制位中1的個數
//統計二進制中1的個數
#include <stdio.h>
int main()
{
int num = 0;
int i = 0;
int sum = 0;
printf("請輸入一個數字:->");
scanf("%d", &num);
for (i = 0; i < 32; i++)
{
sum += (num >> i) & 1;
}
printf("%d中二進制中1的個數為%d\n",num,sum);
return 0;
}
2.列印二進制位的奇數位和偶數位
#include <stdio.h>
int main()
{
int num = 0;
int i = 0;
printf("請輸入一個整數:->");
scanf("%d", &num);
for (i = 31; i >=0; i -= 2)
{
printf("%d", (num>>i) & 1);
}
printf("\n");
for (i = 30; i>=0; i -= 2)
{
printf("%d", (num >> i) & 1);
}
printf("\n");
return 0;
}
3.求兩個數二進制位不同的個數
//求兩個數二進制中不同位的個數
#include <stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
int ret = 0;
int i = 0;
int sum = 0;
printf("請輸入兩個整數:->");
scanf("%d %d", &num1, &num2);
ret = num1 ^ num2;
for (i = 1; i <= 32; i++)
{
sum += ret & 1;
ret >>= 1;
}
printf("%d", sum);
return 0;
}