如何与数组合并并保持可移植性?

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。