简体   繁体   English

以std :: bitset的身份访问std :: uint8_t

[英]Accessing std::uint8_t as std::bitset

I would like to model a status register in C/C++, which should be accessible as std::bitset and as std::uint8_t . 我想在C / C ++中为状态寄存器建模,应该以std :: bitsetstd :: uint8_t对其进行访问。 Thus I would combine them as union as follows: 因此,我将它们结合起来如下:

#include <bitset>
#include <iostream>

union byte {
        std::uint8_t uint;
        std::bitset<8> bitset;
};

int main(int, char*[])
{
        byte b = { .uint = 0b10101010 };

        std::cout << "Value of bit 5: "
                << (b.bitset.test(5) ? "true" : "false") << std::endl;

        std::cout << "Value of bit 4: "
                << (b.bitset.test(4) ? "true" : "false") << std::endl;

        std::cout << "Bitset Output: " << b.bitset << std::endl;
        std::cout << "Uint Output: " << static_cast<int>(b.uint) << std::endl;

        return 0;
}

This seems to work as expected, when compiled with GCC x86_64 8.2 . 使用GCC x86_64 8.2编译时,这似乎按预期工作。 However, I would like to know if I could expect this to work in all cases or if I am better off with some helper functions like bitset , bittest , ... 但是,我想知道我是否可以在所有情况下都能正常工作,或者我是否可以使用一些辅助功能,例如bitsetbittest ,...

What you are trying to do here with union is called type punning and is Undefined Behavior in C++ (you can read more about it in this SO answer ), so it's not guaranteed to work properly even on the same compiler. 您在此处尝试使用union操作称为type punning,并且在C ++中是Undefined Behavior(您可以在此SO Answer中了解更多信息),因此即使在同一编译器上也无法保证其正常工作。

Furthermore, even if it was allowed, std::bitset<8> is not guaranteed to have the same representation as std::uint8_t (and in fact it does not on any major compiler). 此外,即使允许使用,也不能保证std::bitset<8>std::uint8_t具有相同的表示形式(实际上,在任何主要的编译器上都没有)。

In your case, you could just use the regular std::bitset<8> with to_ulong method. 在您的情况下,您可以仅将常规的std::bitset<8>to_ulong方法一起使用。

Another alternative is to have a wrapper class with bitset member that would provide convenience methods to assign/convert to uint8_t . 另一种选择是使用具有bitset成员的包装器类,该包装器类将提供方便的方法来分配/转换为uint8_t

Also, if you only want some limited API of std::bitset<8> , it might be good idea (if you want to keep the size of your class as 1 byte) to wrap around std::uint8_t and implement those few methods (like test ) manually. 另外,如果您只想使用std::bitset<8>某些有限API,则最好将std::uint8_t包裹起来并实现这几种方法(如果您希望将类的大小保持为1个字节)。 (如test )手动。

I took the idea of SomeProgrammerDude's comment 我想到了SomeProgrammerDude的评论

As for your problem, if you want a type that can act as both a native uint8_t and handle bits in a "nice" way, then you have to implement such a class yourself. 对于您的问题,如果您想要一个既可以充当本机uint8_t又可以以“不错”的方式处理位的类型,那么您必须自己实现这样的类。 If you need it to map to a memory-mapped hardware register it should probably wrap a pointer to the register. 如果需要它映射到内存映射的硬件寄存器,则可能应该包装一个指向该寄存器的指针。

and tried to make it in C++. 并尝试用C ++制作。 This is the sample I came up with: 这是我想出的示例:

#include <cassert>
#include <iostream>
#include <iomanip>

class ByteReg {
  private:
    volatile uint8_t &reg;
  public:
    explicit ByteReg(volatile uint8_t &reg): reg(reg) { }
    ByteReg(const ByteReg&) = delete;
    ByteReg operator=(const ByteReg&) = delete;
    ~ByteReg() = default;

    operator uint8_t() { return reg; }
    bool test(int i) const
    {
      assert(i >= 0 && i < 8);
      return ((reg >> i) & 1) != 0;
    }
};

int main() 
{
  volatile uint8_t hwReg = 0xaa; // 0x10101010
  ByteReg reg(hwReg);
  unsigned value = reg;
  std::cout << "reg: 0x" << std::hex << std::setw(2) << std::setfill('0')
    << value << '\n';
  for (int i = 0; i < 8; ++i) {
    std::cout << "bit " << i << ": "
      << (reg.test(i) ? "set" : "unset") << '\n';
  }
  return 0; 
}

Output: 输出:

reg: 0xaa
bit 0: unset
bit 1: set
bit 2: unset
bit 3: set
bit 4: unset
bit 5: set
bit 6: unset
bit 7: set

Live Demo on coliru 在coliru上进行现场演示

Though, a free-standing function testBit() might do as well with even less code: 不过,一个独立的函数testBit()甚至可以用更少的代码来完成:

#include <cassert>
#include <iostream>
#include <iomanip>

bool testBit(uint8_t reg, int i)
{
  assert(i >= 0 && i < 8);
  return ((reg >> i) & 1) != 0;
}

int main() 
{
  volatile uint8_t reg = 0xaa; // 0x10101010
  unsigned value = reg;
  std::cout << "reg: 0x" << std::hex << std::setw(2) << std::setfill('0')
    << value << '\n';
  for (int i = 0; i < 8; ++i) {
    std::cout << "bit " << i << ": "
      << (testBit(reg, i) ? "set" : "unset") << '\n';
  }
  return 0; 
}

Live Demo on coliru 在coliru上进行现场演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM