如何正确从uint16_t变量中提取一个特定位

How to extract one specific bit from a uint16_t variable properly

本文关键字:一个 定位 提取 何正确 uint16 变量      更新时间:2023-10-16

长话短说,我目前正在用C++为一个C库编写一个包装器,该库提取嵌入式系统上寄存器的值。为了监视发生的情况,我需要读取一些寄存器的值,并为每个寄存器制作一个getter。

基本上,我希望我的方法从存储到uint16_t变量中的位返回一个布尔值。在"幼稚"和不含咖啡因的方法上,我正在做这样的事情:

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;
}

我对结果不太满意,我想知道是否有"适当"的方法可以做到这一点......

非常感谢您的建议!

只获取一个位的正常方法是使用按位运算符&。比如 statusRegVal & bitValue .如果设置了位,则结果将等于 bitValue ,这意味着要获得布尔结果,您可以进行简单的比较:statusRegVal & bitValue == bitValue

因此,如果您想检查是否设置了位零(值为 0x0001),那么您可以简单地执行

return statusRegVal & 0x0001 == 0x0001;

为了更好地了解您想要什么,请查看以下链接

屏蔽:https://en.wikipedia.org/wiki/Mask_(计算)和

位操作:https://en.wikipedia.org/wiki/Bit_manipulation

结论:如果你想在变量(寄存器)中读取特定数量的位,你应该用这个变量做一个带有位位置的MASK。假设你有 2Byte 变量 (u16Reg),你想读取位 [5,7],所以, value = ((u16Reg & 0x00A0) >> 5) .在您的情况下,您希望读取一位并返回其状态 TRUEFALSE。

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,以防您的意思是非零是 TRUE。但是,如果 TRUE 表示 0x01,则应将此位移动到 bit[0],如下所示: (0x0200 >> 9) = 0x0001是真的 如果你能理解这一点,你可以让它更简单,比如:

value = ((u16Reg >> n) & 0x0001)

为什么不使用模板:

template<int SHIFT>
bool boolRegVal(uint16_t val) {
   return val & (1 << SHIFT);
}

然后用法:

boolRegVal<4>(statusRegVal);

转换为布尔值将没有帮助,因为它不是 1 位类型。您必须清理其余位,然后检查是否有 0。

你可以做这样的事情:

 bool Busy =  ((statusRegVal >> shift) & 1) ? true : false;

标准库提供用于操作位的 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) 重载以返回引用,因此您也可以分配给它。 bits[4] = false例如。最后,当玩完你的位时:)您可以转换回长(或ulong)或在您的情况下uint16_t value = static_cast<uint16_t>(bits.to_ulong()).向标准图书馆致敬。