二进制文件在写入后读取负整数

时间:2014-10-24 22:24:33

标签: c++ fstream binaryfiles bit-shift

我来自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,而且肯定不是我写的数字! / p>

所以在这里,例如,前两个数字有效,但下一个数字不起作用。例如,上面读取的输出将是:

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

在字节1处,num1应为9.看起来12写得很好但是9&lt;&lt; 4不工作。我端的byteToWrite是byteToWrite -100 'œ'' 我检查了this question我认为有类似的问题,但我觉得我的结尾就在这里。

2 个答案:

答案 0 :(得分: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转换为unsigned char;
  • 将一个掩码应用于shift的结果,只保留你想要的4位。

答案 1 :(得分:1)

问题源于byteToRead >> 4。在C中,任何算术运算都至少以int精度执行。所以首先发生的是byteToRead被提升为int。

这些促销活动是保值的。您的系统已经签名为char,即范围-128127。您的char最初可能是-112(位模式10010000),然后在升级到int后,它保留其值-112(位模式11111...1110010000)。

负值的右移是实现定义的,但常见的实现是进行算术移位&#34;,即执行除以2;因此,您最终会得到byteToRead >> 4-7的结果(位模式11111....111001)。

-7转换为unsigned int会导致UINT_MAX - 6,即4295967289,因为无符号算术被定义为包围mod UINT_MAX+1


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

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