1. 程式人生 > >c語言中的位操作

c語言中的位操作

1.位操作符
(1)位與&:
真值表:1&0=0 1&1=1 0&0=0 0&1=0
從真值表可以看出:位與操作的特點是,只有1和1位於結果為1,其餘全是0.
注意:位與符號是一個&,兩個&&是邏輯與。位與和邏輯與的區別:位與時兩個運算元是按照二進位制位彼次對應位相與的,邏輯與是兩個運算元作為整體來相與的。
(2)位或 |:
真值表:1|0=1 1|1=1 0|0=0 0|1=1
從真值表可以看出:位或操作的特點是:只有2個0相位或才能得到0,只要有1個1結果就一定是1.
注意:位或符號是一個|,兩個||是邏輯或。位或和邏輯或的區別:位或時兩個運算元是按照二進位制位彼次對應位相與的,邏輯或是兩個運算元作為整體來相或的。
(3)位取反~:
真值表:~0=1 ~1=0
按位取反是將運算元的二進位制位逐個按位取反(1變成0,0變成1)
注意:C語言中位取反是~,C語言中的邏輯取反是!。而邏輯取反是真(在C語言中只要不是0的任何數都是真)變成假(在C語言中只有0表示假)、假變成真。
(4)位異或^:
真值表:1^1=0 0^0=0 1^0=1 0^1=1
位異或的特點:2個數如果相等結果為0,不等結果為1。(任何數,其實就是1或者0)與1位異或會取反,與0位異或無變化。
(5)左移位<< 與右移位>>:
C語言的移位要取決於資料型別。
對於無符號數,左移時右側補0(相當於邏輯移位)
對於無符號數,右移時左側補0(相當於邏輯移位)
對於有符號數,左移時右側補0(叫算術移位,相當於邏輯移位)
對於有符號數,右移時左側補符號位(如果正數就補0,負數就補1,叫算術移位)

2.位與位或位異或在操作暫存器時的特殊作用
暫存器的操作要求是:讀改寫三部曲。讀改寫的操作理念,就是:當我想改變一個暫存器中某些特定位時,我不會直接去給他寫,我會先讀出暫存器整體原來的值,然後在這個基礎上修改我想要修改的特定位,再將修改後的值整體寫入暫存器。這樣達到的效果是:在不影響其他位原來值的情況下,我關心的位的值已經被修改了。
(1)特定位清零用&:
位與操作的特點:(任何數,其實就是1或者0)與1位與無變化,與0位與變成0。
如果希望將一個暫存器的某些特定位變成0而不影響其他位,可以構造一個合適的1和0組成的數和這個暫存器原來的值進行位與操作,就可以將特定位清零。
例如:0x12345678要將bit0~bit8清零,0x12345678&0xffffff00即可。
(2)特定位置1用|:
位或操作的特點:任何數,其實就是1或者0)與1位或變成1,與0位或無變化
我們要構造這樣一個數:要置1的特定位為1,其他位為0,然後將這個數與原來的數進行位或即可。
例如:0x12345678要將bit0~bit8置1,0x12345678|0x000000ff即可。
(3)特定位取反用^:
位異或操作的特點:(任何數,其實就是1或者0)與1位異或會取反,與0位異或無變化。
我們要構造這樣一個數:要取反的特定位為1,其他位為0,然後將這個數與原來的數進行位異或即可。
例如:0x12345678要將bit0~bit8取反,0x12345678^0x000000ff即可。

3.如何用位運算構建特定二進位制數
(1)使用移位獲取特定位為1的二進位制數:
最簡單的就是用移位來獲取一個特定位為1的二進位制數。譬如我們需要一個bit3~bit7為1(隱含意思就是其他位全部為0)的二進位制數,可以這樣:(0x1f<<3)
(2)再結合位取反獲取特定位為0的二進位制數:
先試圖構造出這個數的位相反數,再取反得到這個數。譬如我們需要一個bit3~bit7為0(隱含意思就是其他位全部為0)的二進位制數,可以這樣:(~0x1f<<3)

4.位運算實戰演練
(1)用C語言將一個暫存器的bit7~bit17中的值加17(其餘位不受影響)。
思路:第一步,先讀出原來bit7~bit17的值
第二步,給這個值加17
第三步,將bit7~bit17清零
第四步,將第二步算出來的值寫入bit7~bit17
程式碼:
unsigned int a = 0xc30288f8;
//第一步,先讀出原來bit7~bit17的值
unsigned int tmp = 0;
tmp = a & (0x3ff<<7);
tmp >>= 7;
//第二步,給這個值加17
tmp += 17;
//第三步,將a的bit7~bit17清零
a &= ~(0x3ff<<7);
//第四步,將第二步算出來的值寫入bit7~bit17
a |= tmp<<7;
printf(“a = 0x%x.\n”, a);
(2)用巨集定義來完成位運算
①直接用巨集來置位、復位(最右邊為第1位):
程式碼:
#define SET_NTH_BIT(x, n) (x | ((1U)<<(n-1))) //置位
#define CLEAR_NTH_BIT(x, n) (x & ~((1U)<<(n-1))) //復位
②擷取變數的部分連續位:
例如:變數0x88, 也就是10001000b,若擷取第2~4位,則值為:100b = 4
程式碼:
#define GETBITS(x, n, m) ((x & ~(~(0U)<<(m-n+1))<<(n-1)) >> (n-1))
複雜巨集的分析:
(x & ~(~(0U)<<(m-n+1))<<(n-1)) >> (n-1))
第一步,先分清楚這個複雜巨集分為幾部分:2部分
(x & ~(~(0U)<<(m-n+1))<<(n-1)) >> (n-1)
第二步,繼續解析剩下的:又分為2部分
x & ~(~(0U)<<(m-n+1))<<(n-1)
第三步,繼續分析剩下的:
~ (~(0U)<<(m-n+1)) << (n-1)

    參考:朱老師物聯網大講堂    http://www.zhulaoshi.org/