我对按位操作有一定的了解,但是这个功能刚刚过去了。
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
我理解输出没有问题,但我不了解实际过程:
byte = (value & mask) / shift
如何隔离个别位?if(byte & 0x80)
表示“如果字节中的最高位不是0?”byte *= 2;
,mask /= 256;
和shift /= 256;
移动位,为什么此操作有效? 答案 0 :(得分:10)
<强> 1。 byte = (value & mask) / shift
如何隔离单个位?
mask
是一个位模式,总是将8个连续位设置为1,其余位设置为0(它以0xff000000
开头,然后是0x00ff0000
,依此类推。所以当你取mask
和value
的位,value
中的所有位都将设置为0,除了那些与mask
指定的字节对应的位。他们的价值。
shift
设置为相应的值,通过除shift
除法,那些在屏蔽中幸存的位将最终位于最右边的位(请参阅问题3的答案如何工作)。 / p>
因此,假设value
为0xDEADBEEF
,mask
的初始值为0xff000000
,shift
的初始值为256*256*256
。然后value & mask
为0xDE000000
,最终结果为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位。
例如,这些操作用于将值mask
从0xff000000
更改为0x00ff0000
,0x0000ff00
,最后更改为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
,并且想要查看是否设置了最高位,那么and
会0x80
。以下是发生的事情:
11110000 = 0xF0
x 10000000 = 0x80
==========
10000000 = 0x80
因此,如果0xF0
中的最高位未实际设置,则结果为0
而不是0x80
。您可以通过制作二进制数来对任何位位置或位位序列执行此操作。例如,0x88 = 10001000
这将检查字节中的最高位以及第4位。
二进制文件的重要之处在于注意每个位置乘以2。那么00000001 = 1
,然后是00000010 = 2
和00000100 = 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)
听起来你很难看到按位操作与算术有什么关系。
所有这些操作的更好的表示法是使用“真正的”移位运算符:
(value & mask) / (256*256*256)
最好写成
(value & mask) >> (3*8)
这有帮助吗?
我曾经想过使用“DIV”和“MOD”将数字分成两部分 - 其中N DIV 256
是丢弃余数的整数除法 - 所以这有效地向右移8位,丢弃最低字节。相反的是N MOD 256
,其中只取余数。有效AND
s为255,并且只留下最低字节。从DIV
和MOD
结果中,您可以重建原始数字:
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。