如何正确地从 uint16_t 变量中提取一个特定位
How to extract one specific bit from a uint16_t variable properly
长话短说,我目前正在用 C++ 为 C 库编写一个包装器,该库提取嵌入式系统上寄存器的值。为了监控发生了什么,我需要读取一些寄存器的位值并为每个寄存器创建一个 getter。
基本上,我希望我的方法能够将一个位 return 的一个布尔值存储到 uint16_t 变量中。在 'naive' 和不含咖啡因的方法中,我正在做类似的事情:
bool getBusyDevice(int fd) // fd stands for file descriptor, for each instance of the class
{
uint16_t statusRegVal = 0;
get_commandReg(fd, &statusRegVal); // C-library function to get the value of status register
uint16_t shift = 0; // depends on the bit to access - for reusability
bool Busy = (bool) (statusRegVal >> shift);
return busy;
}
我对结果不太满意,我想知道是否有 'proper' 方法可以做到这一点...
非常感谢您的建议!
转换为 bool 不会有帮助,因为它不是 1 位类型。
你必须清理其余的位,然后检查你是否有 0.
你可以这样做:
bool Busy = ((statusRegVal >> shift) & 1) ? true : false;
仅获取一位的正常方法是使用按位 和 运算符 &
。像例如statusRegVal & bitValue
。如果该位已设置,则结果将等于 bitValue
,这意味着要获得布尔结果,您可以进行简单比较:statusRegVal & bitValue == bitValue
.
因此,如果您想检查是否设置了位零(其值为 0x0001
),那么您可以简单地执行
return statusRegVal & 0x0001 == 0x0001;
为什么不使用模板:
template<int SHIFT>
bool boolRegVal(uint16_t val) {
return val & (1 << SHIFT);
}
然后用法:
boolRegVal<4>(statusRegVal);
标准库提供了 std::bitset 用于操作位。这是一个示例,但相信您可以猜出它的作用。
#include <bitset>
#include <iostream>
using namespace std;
int main(int, char**){
typedef bitset<sizeof(int)*8> BitsType; //or uint16_t or whatever
BitsType bits(0xDEADBEEF);
for(int i = 0; i < 5; ++i) //access the bits
cout << "bits[" << i << "] = " << bits[i] << '\n';
cout << "bit[3] = " << bits[3] << '\n'; //original
bits.flip(3);
cout << "bit[3] = " << bits[3] << '\n'; //b[3] = !b[3]
return 0;
}
运算符 [](size_t)
已重载为 return 一个引用,因此您也可以对其进行赋值。 bits[4] = false
例如。最后,当你玩完你的位 :) 你可以转换回 long(或 ulong)或者你的情况 uint16_t value = static_cast<uint16_t>(bits.to_ulong())
。感谢 stdlib。
为了更好地了解您想要什么,请查看以下内容link
屏蔽:https://en.wikipedia.org/wiki/Mask_(computing)
和
位操作:https://en.wikipedia.org/wiki/Bit_manipulation
结论:
如果你想读取变量(寄存器)中的特定位数,你应该用这个带有位位置的变量制作一个掩码。
假设你有 2Byte 变量 (u16Reg) 并且你想读取位 [5,7] 所以,
value = ((u16Reg & 0x00A0) >> 5)
。
在你的情况下,你想读取一位和 return 其状态 TRUE 或 FALSE.
value = ((u16Reg & (0x0001 << n)) >> n)
其中 n 是您要读取的位数。
让我们了解一下。
说 u16Reg = 0x529D = 0b0101001010011101;位[0] = 1 和位[15] = 0;并且您想获得第 9 位。
所以,首先确保除了你的 (9) 之外所有位都是零。
(0b0101001010011101 & (0x0001 << 9)) =
(0b0101001010011101 & 0x0200) =
(0b0101001010011101 & 0b0000001000000000) =
(0b0000001000000000) = 0x0200
这意味着 TRUE,以防您认为 nonZero 是 TRUE。但如果 TRUE 表示 0x01,则应将此位移动到位 [0],如下所示:
(0x0200 >> 9) = 0x0001
为真
如果你能理解这一点,你可以把它变得更简单:
value = ((u16Reg >> n) & 0x0001)
长话短说,我目前正在用 C++ 为 C 库编写一个包装器,该库提取嵌入式系统上寄存器的值。为了监控发生了什么,我需要读取一些寄存器的位值并为每个寄存器创建一个 getter。
基本上,我希望我的方法能够将一个位 return 的一个布尔值存储到 uint16_t 变量中。在 'naive' 和不含咖啡因的方法中,我正在做类似的事情:
bool getBusyDevice(int fd) // fd stands for file descriptor, for each instance of the class
{
uint16_t statusRegVal = 0;
get_commandReg(fd, &statusRegVal); // C-library function to get the value of status register
uint16_t shift = 0; // depends on the bit to access - for reusability
bool Busy = (bool) (statusRegVal >> shift);
return busy;
}
我对结果不太满意,我想知道是否有 'proper' 方法可以做到这一点...
非常感谢您的建议!
转换为 bool 不会有帮助,因为它不是 1 位类型。 你必须清理其余的位,然后检查你是否有 0.
你可以这样做:
bool Busy = ((statusRegVal >> shift) & 1) ? true : false;
仅获取一位的正常方法是使用按位 和 运算符 &
。像例如statusRegVal & bitValue
。如果该位已设置,则结果将等于 bitValue
,这意味着要获得布尔结果,您可以进行简单比较:statusRegVal & bitValue == bitValue
.
因此,如果您想检查是否设置了位零(其值为 0x0001
),那么您可以简单地执行
return statusRegVal & 0x0001 == 0x0001;
为什么不使用模板:
template<int SHIFT>
bool boolRegVal(uint16_t val) {
return val & (1 << SHIFT);
}
然后用法:
boolRegVal<4>(statusRegVal);
标准库提供了 std::bitset 用于操作位。这是一个示例,但相信您可以猜出它的作用。
#include <bitset>
#include <iostream>
using namespace std;
int main(int, char**){
typedef bitset<sizeof(int)*8> BitsType; //or uint16_t or whatever
BitsType bits(0xDEADBEEF);
for(int i = 0; i < 5; ++i) //access the bits
cout << "bits[" << i << "] = " << bits[i] << '\n';
cout << "bit[3] = " << bits[3] << '\n'; //original
bits.flip(3);
cout << "bit[3] = " << bits[3] << '\n'; //b[3] = !b[3]
return 0;
}
运算符 [](size_t)
已重载为 return 一个引用,因此您也可以对其进行赋值。 bits[4] = false
例如。最后,当你玩完你的位 :) 你可以转换回 long(或 ulong)或者你的情况 uint16_t value = static_cast<uint16_t>(bits.to_ulong())
。感谢 stdlib。
为了更好地了解您想要什么,请查看以下内容link
屏蔽:https://en.wikipedia.org/wiki/Mask_(computing) 和
位操作:https://en.wikipedia.org/wiki/Bit_manipulation
结论:
如果你想读取变量(寄存器)中的特定位数,你应该用这个带有位位置的变量制作一个掩码。
假设你有 2Byte 变量 (u16Reg) 并且你想读取位 [5,7] 所以,
value = ((u16Reg & 0x00A0) >> 5)
。
在你的情况下,你想读取一位和 return 其状态 TRUE 或 FALSE.
value = ((u16Reg & (0x0001 << n)) >> n)
其中 n 是您要读取的位数。
让我们了解一下。 说 u16Reg = 0x529D = 0b0101001010011101;位[0] = 1 和位[15] = 0;并且您想获得第 9 位。 所以,首先确保除了你的 (9) 之外所有位都是零。
(0b0101001010011101 & (0x0001 << 9)) =
(0b0101001010011101 & 0x0200) =
(0b0101001010011101 & 0b0000001000000000) =
(0b0000001000000000) = 0x0200
这意味着 TRUE,以防您认为 nonZero 是 TRUE。但如果 TRUE 表示 0x01,则应将此位移动到位 [0],如下所示:
(0x0200 >> 9) = 0x0001
为真
如果你能理解这一点,你可以把它变得更简单:
value = ((u16Reg >> n) & 0x0001)