2013-02-16 70 views
2

我對按位操作有一些熟悉,但是這個功能剛好超過了我的腦海。C中的按位邏輯

void binary_print(unsigned int value) { 
    unsigned int mask = 0xff000000; // Start with a mask for the highest byte. 
    unsigned int shift = 256*256*256; // Start with a shift for the highest byte. 
    unsigned int byte, byte_iterator, bit_iterator; 

    for (byte_iterator=0; byte_iterator < 4; byte_iterator++) { 
    byte = (value & mask)/shift; // Isolate each byte. 
    printf(" "); 

    for (bit_iterator=0; bit_iterator < 8; bit_iterator++) { 
     // Print the byte's bits. 
     if (byte & 0x80) // If the highest bit in the byte isn't 0, 
     printf("1"); // print a 1. 
     else 
     printf("0"); // Otherwise, print a 0. 

     byte *= 2;  // Move all the bits to the left by 1. 
    } 
    mask /= 256;  // Move the bits in mask right by 8. 
    shift /= 256;  // Move the bits in shift right by 8. 
    } 
} 

此函數接收位標誌爲open()功能,並與添加適當的標籤,一個display_flags功能的幫助下產生下面的輸出:

O_RDONLY : 0 : 00000000 00000000 00000000 00000000 
O_WRONLY : 1 : 00000000 00000000 00000000 00000001 
O_RDWR : 2 : 00000000 00000000 00000000 00000010 
O_APPEND : 1024 : 00000000 00000000 00000100 00000000 
O_TRUNC : 512 : 00000000 00000000 00000010 00000000 
O_CREAT : 64 : 00000000 00000000 00000000 01000000 
O_WRONLY|O_APPEND|O_CREAT : 1089 : 00000000 00000000 00000100 01000001 

我沒有問題,理解輸出,但我不明白實際的過程:

  1. byte = (value & mask)/shift如何隔離個別位?
  2. 爲什麼if(byte & 0x80)的意思是「如果字節中的最高位不是0?」
  3. 這些行如何做:byte *= 2;,mask /= 256;shift /= 256;移動位,爲什麼這個操作有意義?

回答

10

1.如何byte = (value & mask)/shift分離單個位?

mask是始終設置爲1,連續8位的位模式,其餘爲0(它開始與0xff000000,然後0x00ff0000,等等。所以,當你把和maskvalue按位,所有來自value的位將被設置爲0,除了那些對應於由mask指定的字節的位。那些保持它們的價值。

shift被設置爲通過與shift分開的相應值,恰好掩蔽後存活的那些位將最終位於最右邊的位(參見問題3的回答如何工作)。

所以假設value0xDEADBEEFmask有其初始值0xff000000,並且shift有其初始值256*256*256。然後value & mask0xDE000000,最終結果爲0x000000DE

在二進制的例子是

value  = 11011110101011011011111011101111 
mask  = 11111111000000000000000000000000 
byte & mask = 11011110000000000000000000000000 
result  = 00000000000000000000000001101111 

2.爲什麼if(byte & 0x80)的意思是「如果字節的最高位不爲0?」

此處代碼作者認爲byte是一個8位變量。儘管技術上較大,但在這裏從不使用較高位。所以當作者提到「最高位」時,想想右邊的第8位(如果byte實際上只有一個字節,那麼最高位應該在那裏)。

現在請注意,0x8010000000二進制。所以當你拿byte & 0x80時,byte的所有位都將被設置爲0,除了「最高」(從右數第八)。所以byte & 0x80是零,如果從byte最高位是零,且大於零,如果從byte「最高」位爲1

3.如何做這些線路:byte *= 2;mask /= 256;shift /= 256;移動位,爲什麼這個操作很重要?

與2相乘相當於將位向左移位1.考慮例如值9,即二進制的1001。乘以2得到18,即二進制的10010

除法類似於2,這是向右移動1.除256除以8等於2,因此除以256等於右移8位。 這些操作在此處用於例如將值mask0xff000000更改爲0x00ff00000x0000ff00,最後更改爲0x000000ff。全功能

有了這些知識的

描述,我們可以看到完整的功能做什麼。在外部循環中,循環遍歷value中的4個字節,從最左邊的一個開始,以最右邊的一個結束。它通過掩蓋當前字節並將其存儲在byte中來實現。

然後內循環遍歷存儲在byte中的8位。它總是從右邊第8位開始,並相應地打印1或0。然後它將這些位向左移動,以便在第二次迭代中,右起第七位的位現在是右起第八位,並且將被打印,然後是下一位等等,直到全部8位以右對齊打印 - 左邊的訂單。

的另一種方式來寫這個功能將是

for (int i = 31; i >= 0; i--) { 
    if (value & (1 << i)) 
    printf("1"); 
    else 
    printf("0"); 

    if (i % 8 == 0) 
    printf(" "); 
} 

這只是通過所有位去從value在左到右的順序。表達式value (1 << i)value中選擇所需的位,從右起第32個(當i爲31時),並以右起第一個(當i爲0時)結束。

+0

非常感謝您對此類詳細的解釋(輕描淡寫)! – Leon 2013-02-16 15:53:10

0

您可以通過乘以或除以2的冪來移動任何二進制值,這就是二進制數學如何工作。

0

好吧,聽起來像你的困難是看到按位運算與算術的關係。

  • 首先,乘以2與將二進制向左移1步相同。其次,如果你多次這樣做,你會向左移動幾個步驟。最後,如果你除以2,你會向右移動一步。

所有這些操作的更好的符號是使用 '真正的' 移位運算符:

(value & mask)/(256*256*256) 

更好寫成

(value & mask) >> (3*8) 

這是否幫助?

我以前喜歡用「DIV」和「MOD」將數字拆分成兩部分的想法 - 其中N DIV 256是丟棄餘數的整數除法 - 所以這有效地向右移位8位,丟棄最低字節。而相反的是N MOD 256,其中只是剩下的。這有效AND由255,並只留下最低字節。從DIVMOD結果,你可以重建你原來的號碼:

LO = X & 255; // equivalent to (byte)X if X is unsigned 
HI = X >> 8 ; // equivalent to (X/256) in this case 
original = LO | (HI << 8) 
// equivalent to LO + (HI * 256), in this case 
0

mask關閉所有打開的位,而不是第一個字節中的所有位,例如,

0110 0000 0000 0000 0000 0000 0000 0110 0000 
& 1111 1111 0000 0000 0000 0000 0000 0000 0000 
= 0110 0000 0000 0000 0000 0000 0000 0000 0000 

因爲1 & 0 or 0 & 1 or 0 & 0 == 0 and 1 & 1 == 0

除以2向右移動所有位,2班他們都離開相乘。

0x80 == 1000 0000所以&與此值關閉除了第一位的一切。

如果設置了第一位,結果值大於0,因此對應於 布爾值爲true,如果不是零,則對應於false。

1

要記住的最重要的事情是bitwise邏輯依賴於在bits上執行操作。因此,對於所有意圖和目的,位& (and)是乘法模1和位| (or)是增加模1.看到這是由例如最簡單的方法:

如果你有一些字節0xF0,你想看看最高位設置你將and它與0x80。這是發生了什麼:

11110000 = 0xF0 
x 10000000 = 0x80 
========== 
    10000000 = 0x80 

因此,如果0xF0最高位實際上並沒有設置,其結果必然是0和代替0x80。您可以通過製作一個二進制數字來完成任何位的位置或位序列。例如,0x88 = 10001000這將檢查字節中的最高位以及第4位。

與二進制重要的是要注意到,每個位置是乘以2。所以00000001 = 1但是然後00000010 = 200000100 = 4等等。所以乘以2就像是一個左移(<<)。除以256是右移(>>)乘以8.這是通過思考兩個冪的最容易看到的。 2^8 = 256。所以,由於每一位都是2之一,因此256的劃分相當於向右移動8(指數/需要的二進制數)。

1

1)值&掩碼會導致除了您感興趣的字節以外的所有字節被清零。 將它除以shift將它移動到字節0(我個人將使用>>操作符)。

2)字節& 0x80刪除除最高位之外的所有位。二進制0x80爲10000000,1位集合與一個字節中的最高位相匹配。結果現在將具有0或10000000(十六進制0x80)的值。只有最高位被設置,IF纔會成立。

3)byte * = 2是左移1位。我會用字節< < = 1。似乎更明顯。

mask/= 256是右移8位。我會使用掩碼>> = 8.同上

如果使用2的冪運算,則可以使用除法和倍數運算符。對我來說,使用移位運算符似乎更加明顯。

該命令重要的是以正確的順序獲取數值。