我可以使用位字段在 C++ 中将 2 * 12 位无符号数字存储为 3 个字节吗?

Can i store 2 * 12bit unsigned numbers in a file as 3 bytes in C++ using bit fields?

我正在使用 C++ 开发 LZW 压缩应用程序。由于没有数据类型可以存储 12 位数字来表示最多 4095 个 table 元素,我认为我可以将其中的 2 个 nrs 作为 3 个字节存储在一个文件中,然后将它们作为一个带有 2 个 unsigned short 的结构读取成员。有没有办法做到这一点,或者我应该只使用 unsigned short?这是我尝试过的方法,但它存储了 4 个字节,因为有 2 个无符号短成员。

#define BITS 12

struct LZWStruct {
    unsigned short code1 : BITS;
    unsigned short code2 : BITS;
};

int main() {
    LZWStruct test;
    test.code1 = 144;
    test.code2 = 233;

    FILE* f = fopen("binary.bin", "wb");
    fwrite(&test, sizeof(test), 1, f);
    fclose(f);
}

here开始,多个相邻的位域通常被打包在一起。大小为零的特殊未命名位域可以强制分解填充。它指定下一个位字段从其分配单元的开头开始。使用 sizeof 验证结构的大小。

但是,确切的打包可能取决于平台和编译器。如果稍后由同一个程序或一些密切相关的程序加载数据,这可能不是什么问题,但对于某些通用格式来说可能是个问题。

你的问题标题和问题 body 是两个不同的问题,答案也不同。

不行,你绝对不能用4个字节(32位)存储3 * 12位无符号数(36位)。

是的,你可以在三个字节(24位)中存储两个12位数字(24位)。

您尝试使用的继承自 C 的 C++ 中的位字段不能准确保证位在结构中的打包方式,因此您无法知道结构中的哪三个字节包含您的数据。您应该简单地使用移位和或运算符将它们放入一个整数中。然后你就会确切地知道要写入文件的三个字节。

然后为了便携,特别是不依赖于机器的字节顺序,你应该使用移位运算符从整数写入字节。如果您使用指向整数的指针编写,它将不可移植。

在您的示例中,您可以尝试 fwrite(&test, 3, 1, f),它可能会起作用, 如果 编译器将代码放在 test 的低位, 如果 你的机器是 little-endian。否则,没有。

所以要可靠地做到这一点:

输入一个整数:

unsigned short code1;
unsigned short code2;
uint32_t test = (code1 & 0x3ff) | ((uint32_t)(code2 & 0x3ff) << 12);

写入文件:

putc(test, f);
putc(test >> 8, f);
putc(test >> 16, f);

如果您愿意,可以跳过中间步骤:

putc(code1, f);
putc(((code1 >> 8) & 0xf) | (code2 << 4), f);
putc(code2 >> 4, f);

(在上面我保证我只用 & 运算符存储每个代码的低 12 位,以防低 12 位以上的位不为零。如果你确定代码值小于4096,则可以去掉上面的&操作。)