我有一个包含 100 个 uint8_t
的数组,它被视为一个 800 位的流,一次处理 7 位。所以换句话说,如果 8 位数组的第一个元素包含 0b11001100
而第二个元素包含 ob11110000
那么当我以 7 位格式读取它时, 7 位数组的第一个元素是 0b1100110
,第二个元素是 0b0111100
,其余 2 位保留在第 3 位。
我尝试的第一件事是 union ...
struct uint7_t {
uint8_t i1:7;
};
union uint7_8_t {
uint8_t u8[100];
uint7_t u7[115];
};
当然,所有内容都是字节对齐的,我最终只是简单地丢失了每个元素的第 8 位。
有人知道我该怎么做吗?
需要说明的是,这是并集结果的可视化表示:
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
8位数据的32位
0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx
7 位数据的 32 位。
这代表了我想做的事情:
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
8位数据的32位
xxxxxxx xxxxxxx xxxxxxx xxxxxxx xxxx
7 位数据的 32 位。
我知道最后的位可能会被填充,但没关系,我只想以某种方式一次访问每个字节 7 位,而不会丢失 800 位中的任何一位。到目前为止,我能想到的唯一方法是大量位移,这当然可行,但我确信有一种更简洁的方法(?)
提前感谢您的回答。
最佳答案
不确定您所说的“清洁工”是什么意思。一般来说,处理这类问题的人通常认为移位和掩蔽是正确的原始工具。可以做一些事情,比如定义一个比特流抽象,用一种方法从流中读取任意数量的比特。这种抽象有时会出现在压缩应用程序中。该方法的内部当然会使用移位和掩码。
一种相当简洁的方法是编写一个函数,该函数在 unsigned char 数组中的任何位索引处提取一个 7 位数字。使用除法将位索引转换为字节索引,并使用取模得到字节内的位索引。然后转移和掩蔽。输入位可以跨越两个字节,因此您要么必须在提取之前将 16 位值粘合在一起,要么进行两次较小的提取和/或将它们组合在一起以构造结果。
如果我的目标是中等性能,我可能会采用以下两种方法之一:
第一个有两个状态变量,表示从当前字节和下一个字节中取出多少位。它将使用移位、掩码和按位或来产生当前输出(例如 0 到 127 之间的数字作为 int),然后循环将通过添加和模数更新两个状态变量,并将递增当前字节指针如果第一个字节中的所有位都被消耗。
第二种方法是将 56 位(相当于输入的 8 个输出)加载到一个 64 位整数中,并使用完全展开的结构来提取 8 个输出中的每一个。在不使用未对齐内存读取的情况下执行此操作需要零碎地构建 64 位整数。 (56 位是特殊的,因为起始位位置是字节对齐的。)
为了真正快速,我可能会尝试在 Halide 中编写 SIMD 代码。我相信这超出了这里的范围。 (并不清楚它实际上会赢得多少。)
一次将多个字节读入整数的设计可能必须考虑处理器字节顺序。
关于c++ - 将 8 位数据作为 7 位数据访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44810381/