c++ - C++ 中的 union 和按位运算

标签 c++ operator-overloading bit-manipulation bitwise-operators unions

我在源代码中看到了如下结构。

template<unsigned bitno, unsigned nbits = 1, typename T = u8>
struct RegBit
{
    T data;
    enum { mask = (1u << nbits) - 1u };
    template<typename T2>
    RegBit& operator=(T2 val)
    {
        data = (data & ~(mask << bitno)) | ((nbits > 1 ? val & mask : !!val) << bitno);
        return *this;
    }
    operator unsigned() const { return (data >> bitno) & mask; }
};

union {
    u8 raw;
    RegBit<0> r0;
    RegBit<1> r1;
    RegBit<2> r2;
    RegBit<3> r3;
    RegBit<6> r6;
    RegBit<7> r7;
} P;

第一次阅读后,我发现类型为 RegBit 的对象的 unsigned 转换将返回位数 bitno + 1 数据

但是,我不明白如何处理 = 重载运算符。我的意思是我理解语法,但不理解按位运算的含义。

最后,如果您运行代码并影响 P.raw 的值,您会注意到 ∀ i ∈ [0;7],P。 ri.data = P.raw

这怎么可能? 当然,代码会做它应该做的事情,即:∀ i ∈ [0;7],(unsigned)P.ri 是第 (i+1) 位P.raw 的。

最佳答案

operator= 是如何工作的?

当您编写 P.r2 = 1; 时,将调用 r2 成员的赋值运算符。所以它会产生 P.r2.operator= (1); 的效果,返回对 P.r2 的引用。

让我们分析一下专用模板中的赋值细节,其中bitno=2nbits=1Tu8:

mask = (1u << nbits) - 1u   
     = (1 shifted by 1 bits, aka binary 10) - 1
     = binary 1  (i.e.  it's a binary number with the n lowest bits set)

让我们逐步分析完整的表达式。首先是左边部分:

mask << bitno ===> binary 100
~(mask << bitno)  ===> binary 1..1011  (aka the bit bitno is set to 0, counting from least significant bit) 
(data & ~(mask << bitno))  ===> the bit bitno is set to 0 in data (thanks to the bitwise &)  

现在表达式的右边部分:

(nbits > 1 ? val & mask : !!val) is a conditional operator:  
   if nbits >1 is true, then it's val&mask, aka the n lowest bits of val
   if not, then it's !!val, aka "not not val" which evalauates to 0 if val is 0 and 1 if val is not 0.  
In our case, it's the second alternative so 0 or 1 depending on val.  
((nbits > 1 ? val & mask : !!val) << bitno)  then shifts the 0 or the 1 by 2 bits.  

现在终于把所有这些结合起来了:

data = (data & ~(mask << bitno)) | ((nbits > 1 ? val & mask : !!val) << bitno);

      = (data with the bit bitno set to 0) ored with (val expressed on one bit in the bit bitno, counting from the least significant )

另外说明,作为位值 0 与位值 x 的或运算结果为位值 x,此表达式将位 bitno 设置为 val(将 val 作为 bool 处理)。

但是 union 应该做什么呢?

union 在相同的内存位置处理它的所有成员(它们都是相同类型的 u8)。

那么根据您的预期,以下输出是什么:

P.raw=0; 
P.r2=1; 
P.r3=0;  
P.r4=1;  
cout << (int)P.raw <<endl;  

编写您的代码片段的乐观主义者当然期望结果为 20(又名二进制 10100)。这可能在许多编译器上都是这样工作的。但实际上,根据标准,这是绝对不能保证的:

9.5/1: In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time.

另外说明,如果您将某些内容存储在 r2 中,您不确定是否会在 r4 中找到相同的值。唯一可以肯定的是,如果你在 r2 中存储了一些东西并且没有在其他成员中存储任何其他东西,你将在 r2 中找到你存储在那里的东西。

union 的替代方案

如果您需要确保便携性,您可以考虑使用 std::bitset或标准 bitfields .

关于c++ - C++ 中的 union 和按位运算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37306963/

相关文章:

c++ - 为什么我应该将 C++ 运算符重载为全局函数(STL 这样做),注意事项是什么?

javascript - 如何从十六进制字符串构建二进制数组

java - 计算长数中设置的位数

c++ - 通过运算符重载访问类属性的快捷方式

c++ - 如何在 C++ 中重载 "operator %"

c++ - 如何将 mat 图像转换为字符串(array 2d<rgb pixel>)?

c++ - C++中的整数赋值

sql - 如何通过按位运算符操作执行 SQL JOIN?

c++ - 短路和括号

c++ - 为什么模板函数中的 std::is_array 不区分 int 和 array 类型?