使用按位运算符将多个值打包到一个 int 中

低级位操作从来都不是我的强项。我将不胜感激,这将有助于理解按位运算符的以下用例。考虑。。。

int age, gender, height, packed_info;

. . .   // Assign values 

// Pack as AAAAAAA G HHHHHHH using shifts and "or"
packed_info = (age << 8) | (gender << 7) | height;

// Unpack with shifts and masking using "and"
height = packed_info & 0x7F;   // This constant is binary ...01111111
gender = (packed_info >> 7) & 1;
age    = (packed_info >> 8);

我不确定这段代码正在完成什么以及如何实现?为什么使用幻数0x7F?如何完成打包和解包?


答案 1

正如评论所说,我们将把年龄,性别和身高打包成15位,格式:

AAAAAAAGHHHHHHH

让我们从这部分开始:

(age << 8)

首先,年龄具有以下格式:

age           = 00000000AAAAAAA

其中每个 A 可以是 0 或 1。

<< 8将位向左移动 8 个位置,并用零填充间隙。因此,您将获得:

(age << 8)    = AAAAAAA00000000

同样地:

gender        = 00000000000000G
(gender << 7) = 0000000G0000000
height        = 00000000HHHHHHH

现在我们想把它们组合成一个变量。运算符通过查看每个位来工作,如果位在任一输入中为 1,则返回 1。所以:|

0011 | 0101 = 0111

如果一个位在一个输入中为 0,则从另一个输入中获取该位。查看 和 ,您会发现,如果其中一个位的位为 1,则其他位为 0。所以:(age << 8)(gender << 7)height

packed_info = (age << 8) | (gender << 7) | height = AAAAAAAGHHHHHHH

现在我们要解压缩这些位。让我们从高度开始。我们想要获取最后 7 位,而忽略前 8 位。为此,我们使用运算符,仅当两个输入位均为 1 时,该运算符才返回 1。所以:&

0011 & 0101 = 0001

所以:

packed_info          = AAAAAAAGHHHHHHH
0x7F                 = 000000001111111
(packed_info & 0x7F) = 00000000HHHHHHH = height

为了获得年龄,我们可以将所有内容向右推8个位置,然后我们就可以了。所以。0000000AAAAAAAAage = (packed_info >> 8)

最后,为了得到性别,我们将所有内容都推到右侧7位以摆脱高度。然后,我们只关心最后一点:

packed_info            = AAAAAAAGHHHHHHH
(packed_info >> 7)     = 0000000AAAAAAAG
1                      = 000000000000001
(packed_info >> 7) & 1 = 00000000000000G

答案 2

这可能是位操作的一个相当长的教训,但首先让我指出维基百科上的位掩码文章

packed_info = (age << 8) | (gender << 7) | height;

取年龄并将其值移动到8位以上,然后取性别并将其移动到7位以上,高度将占据最后一位。

age    = 0b101
gender = 0b1
height = 0b1100
packed_info = 0b10100000000
            | 0b00010000000
            | 0b00000001100
/* which is */
packed_info = 0b10110001100

解压缩会反其道而行之,但会使用0x7F(即 0b 01111111)等掩码来修剪字段中的其他值。

gender = (packed_info >> 7) & 1;

会像...

gender = 0b1011 /* shifted 7 here but still has age on the other side */
       & 0b0001
/* which is */
gender = 0b1

请注意,将任何内容设置为 1 与“保留”该位相同,而使用 0 进行 ANDing 与“忽略”该位相同。


推荐