我试图从一个字节数组中提取一系列5位数据块;或者,基本上,读取一个字节数组,好像它是一个5位块的数组。下面可以看到这个想法的例证:
由于5位和8位的最小公倍数是40位,我创建了一个包含8个5位块和5个元素字节数组的并集,如下所示:
union Converter {
struct {
uint32_t chunk0 : 5;
uint32_t chunk1 : 5;
uint32_t chunk2 : 5;
uint32_t chunk3 : 5;
uint32_t chunk4 : 5;
uint32_t chunk5 : 5;
uint32_t chunk6 : 5;
uint32_t chunk7 : 5;
} __attribute__((packed));
struct {
uint8_t bytes[5];
};
};
请注意,每个块的值稍后将存储在32位无符号整数中,因此uint32_t
用于存储转换器中每个块的值。这种技术背后的想法是,我可以简单地从第一个结构中读取每个块的值,并获得相关的块值。为了将字节数组分配给union,我使用了以下内容:
// Create an array of values
uint8_t someArray[5] = {0xff, 0xff, 0xff, 0xff, 0xff};
// Create a coverter
Converter converter;
// Copy the byte array into the converter
std::memcpy(converter.bytes, someArray, 5);
然后将按如下方式读取块值:
std::cout << "Chunk 0: " << converter.chunk0 << std::endl;
std::cout << "Chunk 1: " << converter.chunk1 << std::endl;
std::cout << "Chunk 2: " << converter.chunk2 << std::endl;
// Continue to the remaining chunks...
问题出现在最后一个块的值上:0-6块中的每一个都计算为31
,这是正确的,但最后一个块的计算结果为7
。相反,它应该是31
。查看内存(注意:我使用的是x64机器,因此是little-endian),我看到以下值:
Address 0 - 3 4 - 7 8 - B C - F
000000000024FE20 FFFFFFFF FF000000 49194000 00000000
有趣的是,如果我将前两个内存块(一个块为4字节组)的值更改为FFFFFFFF FF010000
(将第二个组从FF000000
更改为FF010000
),最后一个块的值从7
变为15
。为了获得最后一个块的31
值,必须将这两个块设置为FFFFFFFF FF070000
。
由于5个字节和8个5位块应该直接重叠,假设没有填充,我的实现错误在哪里?在这种特殊情况下,我被限制使用C ++ 98并试图实现最大效率。
答案 0 :(得分:3)
C ++中的位字段格式不保证不填充。它可能会拒绝使用您的编译器将您的五位块分成两个32位整数。
您需要编写自己的unmangler。