我可以使用union和bitfield进行数据打包

时间:2018-05-19 03:49:19

标签: gcc c++14

我正在为字体创建一个4位和8位颜色编码。这包括前景,背景,样式和格式。我希望使用以下结构来表示4字节包中的数据。我的目的是将其提取为单个uint32_t,可以将其转换为二进制数据并保存在文件中。

这就是我目前所拥有的:

struct font_pack {
    uint8_t : 8;
    struct {
        uint8_t format : 4;
        uint8_t style : 4;
    } header;
    uint8_t foreground;
    uint8_t background;
}

标头包含两个半字节。 format表示颜色代码为4位或8位颜色。 style是一个标志集,用于声明格式化程序,例如粗体和下划线。

然后我使用以下union来获取写入文件的原始二进制文件,以及将数据设置或打印为十六进制。

union font_raw {
    font_pack pack;
    uint32_t data;
}

不幸的是,当我打印出十六进制时,我期待0x04032100时得到0x00120304。这让我觉得在union内不能保证字节对齐,并且字节顺序正在抓住我。我真的只是希望有简单的打包方法,并将数据打包成3个字节。

有没有其他简单的方法可以做到这一点,还是我坚持做一个更传统的功能来打包和拆包?

1 个答案:

答案 0 :(得分:1)

这肯定是一个字节序问题。我猜你是在x86 / x64(类似英特尔)架构上,这是一个小端,并且会将字节从最不重要到最重要。如果您正在相同的体系结构上编写和读取数据(那么小端系统),字节顺序将确保您以相同的顺序读回字节包装,因此您的font_pack成员仍应正确显示。但是,如果您要在big-endian系统上加载这些文件,则需要采用更传统的路线。但是,如果你保证同样的endian-ness,我会选择你的方法。这很优雅:))

编辑:如果您 在不同的字节顺序机器之间进行读取或写入,那么您可以始终执行以下操作:

#ifdef LITTLE_ENDIAN
struct font_pack {
    uint8_t : 8;
    struct {
        uint8_t format : 4;
        uint8_t style : 4;
    } header;
    uint8_t foreground;
    uint8_t background;
}
#else
struct font_pack {
    uint8_t background;
    uint8_t foreground;
    struct {
        uint8_t format : 4;
        uint8_t style : 4;
    } header;
    uint8_t : 8;
}
#endif

然后在x86或类似系统上定义LITTLE_ENDIAN,而不是在big-endian系统上定义。希望有所帮助。