我想在C / C ++中为状态寄存器建模,应该以std::bitset和std::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进行编译时,这似乎按预期工作。但是,我想知道我是否希望它在所有情况下都能正常工作,或者我是否可以使用bitset
,bittest
,...
答案 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 ®
public:
explicit ByteReg(volatile uint8_t ®): 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
尽管如此,一个独立的函数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;
}