【问题标题】:Binary File Reads Negative Integers After Writing二进制文件写入后读取负整数
【发布时间】:2014-10-24 22:24:32
【问题描述】:

我来自this question,我想将 2 个整数写入一个字节,保证在 0-16 之间(每个 4 位)。

现在,如果我关闭文件,然后运行另一个程序,读取....

for (int i = 0; i < 2; ++i)
{
    char byteToRead;
    file.seekg(i, std::ios::beg);
    file.read(&byteToRead, sizeof(char));
    bool correct = file.bad();
    unsigned int num1 = (byteToRead >> 4);
    unsigned int num2 = (byteToRead & 0x0F);
}

问题是,有时这可行,但有时我的第一个数字是负数,而第二个数字一直是 10 或 9,而且它们肯定不是我写的数字!

因此,例如,前两个数字有效,但下一个数字无效。例如,上面读取的输出将是:

At byte 0, num1 = 5 and num2 = 6
At byte 1, num1 = 4294967289 and num2 = 12

在字节 1,num1 应该是 9。看起来 12 写得很好,但 9 byteToWrite -100 'œ'' 我检查了this question,我认为它有类似的问题,但我觉得我的字节序就在这里。

【问题讨论】:

  • 您正在阅读byteToRead,但正在从myNums 构建数字。
  • 问题写错了,谢谢
  • 您可能还想在执行此操作时使用无符号数字,以避免在移动它们时使用符号扩展。
  • 你为什么使用seekp(i/2)
  • 在使用位操作时需要使用unsigned整数,尤其是右移。

标签: c++ fstream binaryfiles bit-shift


【解决方案1】:

右移运算符保留最左边位的值。如果移位前最左位为0,则移位后仍为0;如果为 1,则移位后仍为 1。这允许保留值的符号。

在你的例子中,你将 9 (0b1001) 与 12 (0b1100) 结合起来,所以你写了 0b10011100 (0x9C)。第 7 位是 1。

当 byteToRead 右移时,你得到 0b11111001 (0xF9),但它被隐式转换为 int。从 char 到 int 的转换也保留了值的符号,因此它产生 0xFFFFFFF9。然后隐式 int 被隐式转换为 unsigned int。所以 num1 包含 0xFFFFFFF9 即 4294967289。

有两种解决方案:

  • 在进行右移时将 byteToRead 转换为无符号字符;
  • 对移位结果应用掩码以仅保留所需的 4 位。

【讨论】:

  • char 到 int 的转换发生在右移之前
【解决方案2】:

问题源于 byteToRead &gt;&gt; 4 。在 C 中,任何算术运算都至少以int 精度执行。所以发生的第一件事就是byteToRead被提升为int。

这些促销是保值的。你的系统有普通的char作为签名,即范围-128127。您的 char 最初可能是 -112(位模式 10010000),然后在提升为 int 后,它会保留其值 -112(位模​​式 11111...1110010000)。

负值的右移是实现定义的,但常见的实现是进行“算术移位”,即除以二;所以你最终得到byteToRead &gt;&gt; 4的结果是-7(位模式11111....111001)。

-7 转换为unsigned int 得到UINT_MAX - 6,即4295967289,因为无符号算术被定义为环绕mod UINT_MAX+1


要解决此问题,您需要在执行算术之前转换为无符号。您可以将byteToRead 转换为(或别名)unsigned char,例如:

unsigned char byteToRead;
file.read( (char *)&byteToRead, 1 );

【讨论】:

    猜你喜欢
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 2015-06-16
    • 1970-01-01
    相关资源
    最近更新 更多