编译器如何实现位字段算术?

时间:2011-11-29 15:22:07

标签: c++ gcc bit-manipulation bit-fields

在询问如何做wrapped N bit signed subtraction的问题时,我得到了以下答案:

template<int bits>
int
sub_wrap( int v, int s )
{
    struct Bits { signed int r: bits; } tmp;
    tmp.r = v - s;
    return tmp.r;
}

这很简洁,但编译器将如何实现呢?从this question开始,我认为访问位字段或多或少与手动操作相同,但与本例中的算术结合时又如何呢?它会像一个好的手动比特法一样快吗?

如果有人想要具体,那么“编译器”角色中“gcc”的答案会很棒。我已经尝试过阅读生成的程序集,但它目前已超出我的范围。

2 个答案:

答案 0 :(得分:2)

编译器了解示例中r的大小和确切位置。假设它就像

[xxxxrrrr]

然后

tmp.r = X;

可以,例如被扩展为(b-后缀表示二进制文字,&是按位,|是按位或)

tmp = (tmp & 11110000b)   // <-- get the remainder which is not tmp.r
    | (X   & 00001111b);  // <-- put X into tmp.r and filter away unwanted bits

想象一下你的布局是

[xxrrrrxx]   // 4 bits, 2 left-shifts

扩张可能是

tmp = (tmp    & 11000011b)   // <-- get the remainder which is not tmp.r
    | ((X<<2) & 00111100b);  // <-- filter 4 relevant bits, then shift left 2

X实际上是什么样的,无论是复杂的表述还是仅仅是文字,实际上都是无关紧要的。

如果你的体系结构不支持这样的按位运算,那么仍然存在乘法和除以2的幂来模拟移位,并且这些也可能用于滤除不需要的位。

答案 1 :(得分:2)

如另一个问题所述,无符号包装数学可以完成:

int tmp = (a - b) & 0xFFF;  /* 12 bit mask.  */

写入(12位)位域将完全执行,有符号或无符号。唯一的区别是您可能会从编译器收到警告消息。

对于阅读,你需要做一些不同的事情。

对于无符号数学,这足以做到这一点:

int result = tmp;  /* whatever bit count, we know tmp contains nothing else.  */

int result = tmp & 0xFFF;  /* 12bit, again, if we have other junk in tmp.  */

对于有符号数学,额外的魔力是符号扩展:

int result = (tmp << (32-12)) >> (32-12); /* asssuming 32bit int, and 12bit value. */

所有这一切都是在更广泛的int中复制位域的最高位(第11位)。

这正是编译器对位域所做的工作。无论您是手动编码还是作为位域编码都取决于您,但只需确保您获得正确的数字。

(我没有阅读标准,但我怀疑依靠bitfields在溢出时做正确的事情可能不安全?)