C中的按位逻辑

时间:2013-02-16 14:16:23

标签: c binary operator-keyword bit

我对按位操作有一定的了解,但是这个功能刚刚过去了。

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;移动位,为什么此操作有效?

6 个答案:

答案 0 :(得分:10)

<强> 1。 byte = (value & mask) / shift如何隔离单个位?

mask是一个位模式,总是将8个连续位设置为1,其余位设置为0(它以0xff000000开头,然后是0x00ff0000,依此类推。所以当你取maskvalue的位,value中的所有位都将设置为0,除了那些与mask指定的字节对应的位。他们的价值。

shift设置为相应的值,通过除shift除法,那些在屏蔽中幸存的位将最终位于最右边的位(请参阅问题3的答案如何工作)。 / p>

因此,假设value0xDEADBEEFmask的初始值为0xff000000shift的初始值为256*256*256。然后value & mask0xDE000000,最终结果为0x000000DE

在二进制中,例子是

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

<强> 2。为什么if(byte & 0x80)表示“如果字节中的最高位不是0?”

这里代码作者认为byte是一个8位变量。虽然它在技术上更大,但这里从不使用更高的位。因此,当作者引用“最高位”时,请考虑右边的第8位(如果byte实际上只有一个字节的大小,则会出现最高位)。

现在请注意,0x80是二进制的10000000。因此,当您取byte & 0x80时,byte中的所有位都将设置为0,但“最高”(右起第8位)除外。因此,如果byte & 0x80中的最高位为零,则byte为零,如果byte中的“最高”位为1,则{0}大于零。

第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。然后它将位移到左边,这样在第二次迭代中,右边第7位的位现在是右边的第8位,将被打印,然后是下一位等,直到所有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时),从右边的第1位开始(i时为0)。

答案 1 :(得分:1)

最重要的是要记住bitwise逻辑依赖于对bits执行操作。因此,对于所有意图和目的,按位& (and)是乘法模1,按位| (or)是加法模1。最简单的方法是看看:

如果你有一些字节0xF0,并且想要查看是否设置了最高位,那么and0x80。以下是发生的事情:

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

因此,如果0xF0中的最高位未实际设置,则结果为0而不是0x80。您可以通过制作二进制数来对任何位位置或位位序列执行此操作。例如,0x88 = 10001000这将检查字节中的最高位以及第4位。

二进制文件的重要之处在于注意每个位置乘以2。那么00000001 = 1,然后是00000010 = 200000100 = 4,依此类推。因此,乘以2就像左移(<<)一样。除以256是右移(>>)乘以8。通过以2的幂来思考,这是最容易看到的。 2^8 = 256。因此,由于每个位都是2之一,256的除法相当于右移8(指数/所需的二进制数)。

答案 2 :(得分:1)

1)价值&amp;掩码导致所有字节被清零,除了您感兴趣的字节。 除以shift将其移动到字节0(我个人会使用&gt;&gt;运算符)。

2)字节&amp; 0x80删除除最高位之外的所有位。 0x80是二进制10000000,1位设置匹配字节中的最高位。现在结果的值为0或10000000(十六进制0x80)。只有在设置了最高位时,IF才会成立。

3)byte * = 2是左移1位。我会使用byte&lt;&lt; = 1.似乎更明显。

mask / = 256是右移8位。我会使用mask&gt;&gt; = 8. ditto

如果你使用2的幂,那么

除数和倍数可以用作移位运算符。对我来说使用移位运算符似乎更明显。

顺序对于以正确的顺序输出值很重要。

答案 3 :(得分:0)

您可以通过乘以或除以2的幂来移动任何二进制值,这就是二进制数学的工作方式。

答案 4 :(得分:0)

听起来你很难看到按位操作与算术有什么关系。

  • 首先,乘以2与向左移动二进制1步相同。
  • 其次,如果你多次这样做,你可以向左移几步。
  • 第三,如果你除以2,你就向右移一步。

所有这些操作的更好的表示法是使用“真正的”移位运算符:

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

最好写成

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

这有帮助吗?

我曾经想过使用“DIV”和“MOD”将数字分成两部分 - 其中N DIV 256是丢弃余数的整数除法 - 所以这有效地向右移8位,丢弃最低字节。相反的是N MOD 256,其中取余数。有效AND s为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

答案 5 :(得分: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,如果不是,则为0,对应于false。