我这里有一些代码,并不真正理解">>"和"&".有人可以澄清吗?
buttons[0] = indata[byteindex]&1;
buttons[1] = (indata[byteindex]>>1)&1;
rawaxes[7] = (indata[byteindex]>>4)&0xf;
Run Code Online (Sandbox Code Playgroud)
Sim*_*ele 16
这些是按位运算符,这意味着它们对构成值的二进制位进行操作.有关详细信息,请参阅Wikipedia上的按位操作.
&是为了AND
如果indata[byteindex]是数字4,那么在二进制中它看起来像00000100.将该数字与1一起给出0,因为第1位未设置:
00000100 AND 00000001 = 0
Run Code Online (Sandbox Code Playgroud)
如果值为5,那么你会得到这个:
00000101 AND 00000001 = 1
Run Code Online (Sandbox Code Playgroud)
允许任何与掩码匹配的位.
>>适用于右移
右移将位向右移位!
00010000 >> 4 = 00000001
Run Code Online (Sandbox Code Playgroud)
Mik*_*one 13
用于提取位字段的标准模式之一是(reg >> offset) & mask,reg您正在读取的寄存器(或其他存储器位置),offset您跳过的最低有效位数是多少,并且mask是重要的位集.>> offset如果offset是0 mask通常等于2 宽度 -1,或者(1 << width) - 1在C中,width则该步骤可以省略,其中是该字段中的位数.
所以,看看你有什么:
buttons[0] = indata[byteindex]&1;
Run Code Online (Sandbox Code Playgroud)
这里offset是0(它被省略)并且mask是1.因此,这只是最不重要的位indata[byteindex]:
bit number -> 7 6 5 4 3 2 1 0
+-+-+-+-+-+-+-+-+
indata[byteindex] | | | | | | | |*|
+-+-+-+-+-+-+-+-+
|
\----> buttons[0]
Run Code Online (Sandbox Code Playgroud)
下一个:
buttons[1] = (indata[byteindex]>>1)&1;
Run Code Online (Sandbox Code Playgroud)
这里offset是1并且width是1 ...
bit number -> 7 6 5 4 3 2 1 0
+-+-+-+-+-+-+-+-+
indata[byteindex] | | | | | | |*| |
+-+-+-+-+-+-+-+-+
|
\------> buttons[1]
Run Code Online (Sandbox Code Playgroud)
最后:
rawaxes[7] = (indata[byteindex]>>4)&0xf;
Run Code Online (Sandbox Code Playgroud)
这里offset是4并且width是4(2 4 -1 = 16 - 1 = 15 = 0xf):
bit number -> 7 6 5 4 3 2 1 0
+-+-+-+-+-+-+-+-+
indata[byteindex] |*|*|*|*| | | | |
+-+-+-+-+-+-+-+-+
| | | |
\--v--/
|
\---------------> rawaxes[7]
Run Code Online (Sandbox Code Playgroud)
编辑...
但我不明白它的意义是什么......
迈克拉起一把摇椅坐下.
在过去的8位CPU中,计算机通常具有64K(65 536字节)的地址空间.现在我们想用我们花哨的机器来做尽可能多的事情,所以我们会做一些事情,比如购买64K的RAM并将所有内容映射到RAM.Shazam,64K的RAM和吹牛的权利到处都是.
但是只能访问RAM的计算机并不是很好.它需要OS(或至少一个BIOS)的一些ROM,以及I/O的一些地址.(你在后面 - siddown.我知道英特尔芯片有单独的I/O地址空间,但它没有帮助,因为I/O空间远远小于内存空间,所以你遇到了相同的约束.)
用于ROM和I/O的地址空间是无法作为RAM访问的空间,因此您希望最小化RAM未使用的空间.因此,例如,当您的I/O外设有五个不同的东西,其状态总计为一个位时,而不是给这些位中的每一个自己的字节(因此,地址),他们得到了包装的绝妙主意所有这五个位都转换成一个字节,留下三个没有做任何事情的位.Voila,中断状态寄存器诞生了.
硬件设计人员也对地址位越少导致地址位越少(因为地址位是地址数量的log-base-2的上限)感到印象深刻,这意味着芯片上的地址引脚更少,从而将引脚释放用于其他目的.(这些是48针芯片被认为很大,64针巨大的时代,并且网格阵列封装是不可能的,因为多层电路板非常昂贵.这也是多路复用地址和数据的前几天在相同的引脚上变得司空见惯.)
因此,芯片被录制和制造,并且硬件被构建,然后它落到程序员手中以使硬件工作.而且,程序员说,"WTF?我只是想知道在血腥的串口中是否有一个字节需要读取,但是所有这些其他位都像"接收器溢出"一样." 硬件人员考虑了这一点,并说,"坚韧的饼干,处理它."
所以程序员去了Guru,那个没有忘记他的布尔代数并且很高兴不写COBOL的人.Guru说,"使用Bit AND操作来强制你不关心的那些位.如果你需要一个数字,而不仅仅是零或非零,那么使用逻辑右移(LSR)结果." 他们试了一下.虽然更聪明的人开始对读取 - 修改 - 写入周期中的竞争条件等事情感到疑惑,但它仍然很有效,但这是另一个时间的故事.
因此,将松散或完全不相关的位打包到寄存器中的技术变得司空见惯.开发协议的人们总是希望使用更少的比特,他们也跳过了这些技术.因此,即使在今天,凭借我们的千兆字节RAM和千兆位带宽,我们仍然可以打包和解压缩位域,其中的表达式与键盘头敲击相关.
(是的,我知道位字段可能会回到ENIAC,甚至可能是差异引擎,如果Lady Ada需要将两个数据元素填充到一个寄存器中,但是我还没那么长时间活着,好吗?我坚持我知道的.)
(硬件设计人员注意到:对于打包驱动程序编写者想要独立使用的状态标志和控制位这样的事情,实际上没有多少理由.我已经做了几个设计,每个32位寄存器有一位很多情况下,没有一点移位或屏蔽,没有种族,驱动程序代码更易于编写和理解,地址译码逻辑是平凡的更为复杂.如果驱动程序是复杂的,简化的标志和位处理可以节省你很多的ROM和CPU周期.)
(更随机的琐事:Atmel AVR架构(在Arduino中使用,在许多其他地方)有一些专门的位设置和位清除指令.该avr-libc库用于为这些指令提供宏,但现在gcc编译器足够智能认识到这reg |= (1 << bitNum);是有点设置并且reg &= ~(1 << bitNum);有点清楚,并且输入正确的指令.我确信其他架构也有类似的优化.)