我可以使用位字段在 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,则可以去掉上面的&
操作。)
我正在使用 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,则可以去掉上面的&
操作。)