从一个字节中获取n个位

26
我遇到了一些抓取字节中n位的小麻烦。
我有一个无符号整数。假设我们的十六进制数字是0x2A,即十进制数42。在二进制中它看起来像这样:0010 1010。如何获取前五位(00101)和接下来的三位(010),并将它们放入单独的整数中?
如果有人能帮助我,那就太好了!我知道如何从一个字节中提取,只需执行
int x = (number >> (8*n)) & 0xff // n being the # byte

我在Stack Overflow的另一个帖子上看到了这个,但我不确定如何从字节中获取单独的位。如果有人能帮我解决问题,那就太好了!谢谢!


42的前5位(MSB)为00000,因为int类型总是超过1个字节。此外,并不存在十六进制表示形式为十进制无符号整数的情况。int a = 0x2A; 等同于写成 int a = 42;. - user93353
6个回答

29

整数在计算机中以一系列位的形式表示;幸运的是,对于我们人类来说,编程语言提供了一种机制,可以将这些数字显示为十进制(或十六进制),但这并不改变它们的内部表示。

您应该查看按位运算符 &、|、^ 和 ~,以及移位运算符 << 和 >>,这将帮助您理解如何解决像这样的问题。

整数的最后3位是:

x & 0x7

从倒数第八位开始的五个比特为:
x >> 3    // all but the last three bits
  &  0x1F // the last five bits.

这种方法在性能方面与将两个子整数仅存储为两个32位整数相比如何?提取需要一些时间,但它会慢32个操作吗? - Kammeot
@InspiredOne:像这样的问题在抽象情况下无法精确回答,但很明显它可以提高内存使用效率(相对于两个32位整数,可以提高8倍,或者相对于两个字节,可以提高2倍),这将改善缓存性能、内存吞吐量和带宽(如果相关,如传输时间或二级存储)。由于CPU成本相比这些因素微不足道,所以只要需要多个实例,压缩数据通常会更快;对于单个变量对来说这做起来没有太大价值(但也不会有太多损失)。 - rici

19
在 C 语言中,“抓取”整数类型的部分可以按照以下方式进行操作:
  1. 将您想要的位移动到最低位置。
  2. 使用 & 掩码来选择您想要的位 - 1 表示“复制此位”,0 表示“忽略此位”。
所以,在您的示例中,假设我们有一个数字 int x = 42;
第一个 5 位:
(x >> 3) & ((1 << 5)-1);

或者

(x >> 3) & 31;

获取低三位:
(x >> 0) & ((1 << 3)-1)

或者:

x & 7;

12

假设你想从顶部获取hi位,从底部获取lo位。(在你的示例中为5和3)

top = (n >> lo) & ((1 << hi) - 1)
bottom = n & ((1 << lo) - 1)

解释:

对于“top”,首先要去掉低位(向右移位),然后使用“全1”掩码遮盖剩余部分(如果您有一个类似于0010000的二进制数,减去1会得到0001111 - 与原始数字中0的数量相同的1数量)。

对于底部也是同样的方法,只是不需要关心初始移位。

top = (42 >> 3) & ((1 << 5) - 1) = 5 & (32 - 1) = 5 = 00101b
bottom = 42 & ((1 << 3) - 1) = 42 & (8 - 1) = 2 = 010b

8
你可以使用位域来实现这个功能。位域是一种特殊的结构体,你可以在其中按位指定变量。
typedef struct {
  unsigned char a:5;
  unsigned char b:3;
} my_bit_t;

unsigned char c = 0x42;
my_bit_t * n = &c;
int first = n->a;
int sec = n->b;

位域的详细说明请参见http://www.cs.cf.ac.uk/Dave/C/node13.html#SECTION001320000000000000000
位域的魅力在于,您无需处理移位运算符等。表示法非常简单。与操作位一样,存在可移植性问题。

2

int x = (number >> 3) & 0x1f;

这将给您一个整数,其中最后5位是number的8-4位,其他位为零。

同样地,

int y = number & 0x7;

这将给您一个整数,其中最后3位设置为number的最后3位,其余位为零。


1

在你的代码中去掉8*。

int input = 42;
int high3 = input >> 5;
int low5 = input & (32 - 1); // 32 = 2^5
bool isBit3On = input & 4; // 4 = 2^(3-1)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接