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

时间:2015-11-28 16:51:49

标签: c++ arrays unions

我试图从一个字节数组中提取一系列5位数据块;或者,基本上,读取一个字节数组,好像它是一个5位块的数组。下面可以看到这个想法的例证:

enter image description here

由于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并试图实现最大效率。

1 个答案:

答案 0 :(得分:3)

C ++中的位字段格式不保证不填充。它可能会拒绝使用您的编译器将您的五位块分成两个32位整数。

您需要编写自己的unmangler。