我正在开发一个函数,该函数接收一个字节并需要更改该字节中的某些位。
例如函数接收:
11001011
然后我需要将 MSB 设置为 0,这很简单:
buffer[0] &= ~(1 << 7);
但随后我需要将位 6 到 3(我在这里将 LSB 称为位 0)设置为提供给函数的参数。此参数可以是从 0 到 6 的整数。
重要的是我不应该更改任何其他位。
我尝试过使用 mask 之类的东西,但我惨遭失败。然后作为最后的手段,我像下面那样痛苦地做了。它工作正常......但它很丑并且会生成大量指令,使代码运行缓慢:
switch(regAddress) {
case 0:
buffer[0] &= ~(1 << 5);
buffer[0] &= ~(1 << 4);
buffer[0] &= ~(1 << 3);
break;
case 1:
buffer[0] &= ~(1 << 5);
buffer[0] &= ~(1 << 4);
buffer[0] |= (1 << 3);
break;
//YOU GOT THE IDEA!!.....
}
请让我知道如何在一(或两)行代码中执行此操作,以便我学习技巧。
我犯了一个错误,传递的参数总是 0 到 6,所以我想设置的 4 位的 MSB 总是零,因此在 switch case 之前我喜欢:
//because we only have 7 address, we already set the 4th bit to 0
buffer[0] &= ~(1 << 6);
最佳答案
如果你有一个位域,比如第 6 位到第 3 位(总共四位),打包成一个值 w
(某种类型的无符号整数),然后您可以使用值 v
设置字段与:
w = (w & ~0x78) | (v << 3);
这假设v
在要求的范围内。如果没有,您可以使用 (v & 0xf)
代替 v
.掩码操作w & ~0x78
清除第 6 位到第 3 位,移位操作移动 v
到适当的位置,按位或操作将它们组合起来。
从w
中提取字段,你可以使用:
(w >> 3) & 0xf
移位操作右对齐字段,掩码操作清除字段外的位。这相当于:
(w & 0x78) >> 3
此版本在移动前屏蔽该字段(因此它使用更大的屏蔽值)。
确保w
具有无符号类型,因此移位是无符号的。
注意:此示例是针对占用第 6、5、4、3 位的 4 位字段。 0x78
面具是((1 << 4) - 1) << 3
,即 0xf << 3
. 0xf
面具是(1 << 4) - 1
.和移位量,3
, 是字段右侧的位数,即位 2、1 和 0。
关于更改字节中的特定位集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47128112/