我正在查看NIC的数据表规范,并说:
寄存器的2:3位包含NIC速度,4包含链接状态等。如何使用按位隔离这些位?
例如,我已经看到了隔离链接状态的代码,如:
(link_reg&(1<<#4))>> 4
但我不明白为什么正确的转变。我必须说,即使我理解如何转换为二进制文件以及每个操作的作用,我对bitwise运算仍然不太满意,但它并不像实际那样响。
答案 0 :(得分:2)
这取决于你想用这个位做什么。链接状态,称之为L在一个变量/寄存器
43210
xxxxLxxxx
要隔离您想要的位,并使用1,按位操作:
xxLxxxx
& 0010000
=========
00L0000
1<<< 4 = 1,带有4个零或0b10000,您想要和的数字。
status&(1<<4)
这将产生零或0b10000的结果。您可以进行布尔比较以确定它是假(零)还是真(非零)
if(status&(1<<4))
{
//bit was on/one
}
else
{
//bit was off/zero
}
如果您希望结果为1或0,则需要将结果移至1列
(0b00L0000 >> 4) = 0b0000L
如果和的结果为零,则移位仍为零,如果结果为0b10000,则右移4为0b00001
所以
(status&(1<<4))>>4 gives either a 1 or 0;
(xxxxLxxxx & (00001<<4))>>4 =
(xxxxLxxxx & (10000))>>4 =
(0000L0000) >> 4 =
0000L
使用更少操作执行此操作的另一种方法是
(status>>4)&1;
xxxxLxxxx >> 4 = xxxxxxL
xxxxxxL & 00001 = 00000L
答案 1 :(得分:1)
最容易查看一些二进制数字。
这是一个可能的寄存器值,位索引在下面:
00111010
76543210
所以,第4位是1.我们怎么得到这一点?我们构造一个只包含该位的掩码(我们可以通过将1移到正确的位置来做,即1<<4
),然后使用&
:
00111010
& 00010000
----------
00010000
但我们想要一个0或1.因此,一种方法是将结果向下移动:00010000 >> 4 == 1
。另一个替代方案是!!val
,它将0变为0,非零变为1(请注意,这仅适用于单个位,而不是像链接速度那样的两位值。)
现在,如果你想要比特3:2,你可以使用掩码同时设置这两个比特。您可以编写3 << 2
来获取00001100
(因为3设置了两个位)。然后我们&
用它:
00111010
& 00001100
----------
00001000
并向下移2以得到10
,即所需的两位。因此,获得两位链接速度的语句将是(link_reg & (3<<2))>>2
。
答案 2 :(得分:0)
您可以使用它来确定位置pos
中的位是否设置在val
中:
#define CHECK_BIT(val, pos) ((val) & (1U<<(pos)))
if (CHECK_BIT(reg, 4)) {
/* bit 4 is set */
}
如果两个操作数都将相应的位设置为1,则按位和运算符(&amp;)将结果中的每个位设置为1.否则,结果位为0.
答案 3 :(得分:0)
如果您想将第2位和第3位(从0开始计数)视为数字,您可以这样做:
unsigned int n = (link_get & 0xF) >> 2;
bitwise和15(二进制为0b1111)将除了底部四位之外的所有位设置为零,并且随后的右移2将获得位2和3中的数字。
答案 4 :(得分:0)
问题是隔离位是不够的:您需要移动它们以获得值的正确大小顺序。
在您的示例中,您有第2位和第3位的大小(I&#39; m假设最低有效位是位0),这意味着它是范围[0,3]中的值。现在,您可以使用reg & (0x03<<2)
或转换后的(reg & 0x12)
屏蔽这些位,但这还不够:
reg 0110 1010 &
0x12 0000 1100
---------------
0x08 0000 1000
如您所见,结果是1000b
,即8,超出了范围。要解决此问题,您需要移回结果,以便您感兴趣的值的最低有效位对应于包含字节的最低有效位:
0000 1000 >> 2 = 10b = 3
现在是正确的。