c++ - 将 8 位数据作为 7 位数据访问

标签 c++ arrays unions 8-bit 7-bit

我有一个包含 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/

相关文章:

c# - 如何在运行时指定 [DllImport] 路径?

c++ - 将两个字节转换为 16 位值的最有效方法?

javascript - 从 javascript 数组中提取纬度/经度数据

c - 通过指针访问 C union 成员

c - 为什么 a 和 b 在这段代码中没有交换?

c++ - 如何优化 C++ for loops/if 语句?

带逻辑运算符的子表达式的 C++ 求值顺序

javascript - 循环遍历对象数组中的每个属性

java - 创建深拷贝方法,Java

c++ - 一个得到良好支持的 c++ union 的替代方案?