如何与数组合并并保持可移植性?
How to union with an array and maintain portability?
我正在尝试从字节数组中提取一系列 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
用于在转换器中存储每个块的值。这种技术背后的想法是,我可以简单地从第一个结构中读取每个块的值并获得关联的块值。为了将字节数组分配给联合,我使用了以下内容:
// 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 机器,因此是小端),我看到以下值:
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 并试图实现最大效率。
C++ 中的位域格式不保证没有填充。它可能拒绝使用您的编译器将您的五位块拆分为两个 32 位整数。
您需要编写自己的 unmangler。
我正在尝试从字节数组中提取一系列 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
用于在转换器中存储每个块的值。这种技术背后的想法是,我可以简单地从第一个结构中读取每个块的值并获得关联的块值。为了将字节数组分配给联合,我使用了以下内容:
// 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 机器,因此是小端),我看到以下值:
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 并试图实现最大效率。
C++ 中的位域格式不保证没有填充。它可能拒绝使用您的编译器将您的五位块拆分为两个 32 位整数。
您需要编写自己的 unmangler。