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

时间:2018-09-10 11:52:48

标签: c++ c++11 unions bitset

我想在C / C ++中为状态寄存器建模,应该以std::bitsetstd::uint8_t的形式访问状态寄存器。因此,我将它们结合起来如下:

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

使用GCC x86_64 8.2进行编译时,这似乎按预期工作。但是,我想知道我是否希望它在所有情况下都能正常工作,或者我是否可以使用bitsetbittest,...

2 个答案:

答案 0 :(得分:4)

您在这里尝试使用union进行的操作称为类型调整,在C ++中是未定义的行为(您可以详细了解in this SO answer),因此即使在相同的编译器。

此外,即使允许使用,std::bitset<8>也不能保证与std::uint8_t具有相同的表示形式(实际上,在任何主要的编译器上都没有)。

在您的情况下,您可以仅将常规std::bitset<8>to_ulong方法一起使用。

另一种选择是使用具有bitset成员的包装器类,该包装器类将提供方便的方法来分配/转换为uint8_t

此外,如果您只想使用std::bitset<8>的有限API,则最好将std::uint8_t包裹起来并实现它们(如果您希望将类的大小保持为1字节)几种方法(例如test)。

答案 1 :(得分:2)

我想到了SomeProgrammerDude的评论

  

对于您的问题,如果您想要一个既可以充当本机uint8_t又可以以“不错”的方式处理位的类型,那么您必须自己实现这样的类。如果您需要它映射到内存映射的硬件寄存器,则可能应该包装一个指向该寄存器的指针。

并尝试用C ++制作。这是我想出的示例:

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

输出:

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

尽管如此,一个独立的函数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