C中的按位逻辑

我对按位操作有一定的了解,但这个function只是我的头脑。

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; 移动位,为什么这个操作有意义?

1. byte = (value & mask) / shift隔离各个位?

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

shift设置为相应的值,通过shift划分确切地说,那些在屏蔽中幸存的位将最终位于最右边的位中(请参阅问题3的答案如何工作)。

因此假设value 0xDEADBEEFmask的初始值为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实际上只有一个字节大小,则会出现最高位)。

现在请注意, 0x80是二进制的10000000 。 因此,当你取byte & 0x80 ,来自byte所有位将被设置为0,除了“最高”(右起第8位)之一。 因此,如果byte的最高位为零,则byte & 0x80为零,如果byte中的“最高”位为1,则大于零。

3.这些行如何: byte *= 2; mask /= 256; 并且shift /= 256; 移动位,为什么这个操作有意义?

乘以2相当于向左移位1.用例如值9,二进制为1001 。 乘以2得到18,二进制为10010

类似于除以2,这是向右移位1.除以256相当于8除以2,因此除以256相当于右移8位。 这里使用这些操作例如将值mask0xff000000更改为0x00ff0000 ,最后更改为0x000000ff

完整function的描述

有了这些知识,我们就可以看到完整function的作用。 在外部循环中,它循环遍历4个字节的value ,从最左边的一个开始到最右边的一个结束。 它通过屏蔽当前字节并将其存储在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时)。

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

如果您有一些字节0xF0并且您想要查看是否设置了最高位,那么您将使用0x80 。 这是发生的事情:

  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(指数/所需的二进制数)。

1)值和掩码导致所有字节被清零,除了你感兴趣的字节之外。将它除以移位将其移动到字节0(个人我会使用>>运算符)。

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

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

mask / = 256是右移8位。 我会用mask >> = 8. ditto

如果你使用2的幂,则除数和倍数可以用作移位运算符。对我来说使用移位运算符似乎更明显。

该命令对于以正确的顺序获取值很重要。

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

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

  • 首先,乘以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 

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。