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的幂运算,则可以使用除法和倍数运算符。对我来说,使用移位运算符似乎更加明显。

该命令重要的是以正确的顺序获取数值。