嵌入式场景下:如何高效将Vec<u8>打包为仅用15位的Vec<u16>
解决方案:基于位流打包的高效编码解码实现
由于每个u16的最高位会丢失,实际每个存储单元可用15位有效空间。为最大化存储空间利用率,我们可以将原始Vec<u8>的比特流连续拼接,再按每15位分割为一个u16(最高位固定为0,因为会被覆盖);解码时则反向操作,提取每个u16的低15位拼接回比特流,再分割为u8。
编码函数(Vec<u8> → Vec<u16>)
fn encode(orig: &[u8]) -> Vec<u16> { let mut result = Vec::new(); // 缓冲区存储未处理的比特,u32足够容纳最多14位剩余 + 8位新输入 = 22位 let mut buffer: u32 = 0; let mut buffer_bits = 0; for &byte in orig { // 将当前u8加入缓冲区,左移腾出低位空间 buffer = (buffer << 8) | u32::from(byte); buffer_bits += 8; // 当缓冲区比特数≥15时,提取前15位 while buffer_bits >= 15 { buffer_bits -= 15; // 取出高15位:缓冲区右移剩余比特数,取低15位 let chunk = (buffer >> buffer_bits) & 0x7FFF; // 0x7FFF是15位全1的掩码 result.push(chunk as u16); // 保留剩余比特在缓冲区 buffer &= (1 << buffer_bits) - 1; } } // 处理剩余的比特,补0到15位 if buffer_bits > 0 { let chunk = buffer << (15 - buffer_bits); result.push(chunk as u16); } result }
解码函数(Vec<u16> → Vec<u8>)
fn decode(encoded: &[u16]) -> Vec<u8> { let mut result = Vec::new(); let mut buffer: u32 = 0; let mut buffer_bits = 0; for &word in encoded { // 提取u16的低15位(最高位已丢失,直接忽略) let bits = u32::from(word) & 0x7FFF; // 将15位加入缓冲区 buffer = (buffer << 15) | bits; buffer_bits += 15; // 当缓冲区比特数≥8时,提取前8位 while buffer_bits >= 8 { buffer_bits -= 8; // 取出高8位转为u8 let byte = (buffer >> buffer_bits) as u8; result.push(byte); // 保留剩余比特 buffer &= (1 << buffer_bits) - 1; } } // 剩余不足8位的比特是编码时补的0,直接丢弃 result }
关键说明
- 空间利用率:每个u16使用15位有效空间,存储效率为
15/16 ≈ 93.75%,远高于“单个u8存一个u16”的50%利用率。 - 资源友好:仅使用固定大小的缓冲区(u32),无需额外分配大内存,适配嵌入式环境的有限资源。
- 位操作安全:使用掩码
0x7FFF确保只操作有效15位,规避最高位丢失带来的数据错误。
内容的提问来源于stack exchange,提问作者Kaiden Prince
相关产品推荐
相关产品推荐

