以下问题让我很困惑:
我正在试验doubles
,尤其是他们的特殊情况。像PositiveInfinity
这样的值存储在一个文件中,这没问题。我通过三个简单步骤完成了这项工作:创建double
;把它写进文件;将文件读入byte
- 数组。这很简单,现在我知道Double.NaN
如何以二进制格式显示:)
但后来我发现了以下内容:
根据.Net-Framework,有一个NegativeZero
:
internal static double NegativeZero = BitConverter.Int64BitsToDouble(unchecked((long)0x8000000000000000));
它的表示方式非常简单(遵循IEEE 754):
long
表示二进制数:10000000 ...
第一位表示double
为负数。那么代表NegativeZero
的事件是- 0 * 2^0
,因为尾数和指数都是0
。
代表'正常'然后,0将是64位全部设置为0
。
但问题是将这些数字读入byte
数组。我对NegativeZero
的所有内容如下:128
0
0
... [二进制:100000 ...]
但实际上这是错误的方式:0
0
... 128
! [二进制:00000 ... 0 10000000]
我的第一个想法是:'也许File.ReadAllBytes()
以错误的顺序返回(这将是尴尬的)'。所以我决定用string
测试阅读器( - >创建一个带字符串的文件;将其读入byte
数组)
结果很好:'你好'仍然是'你好''在byte
数组中,而不是上面提到的例子' olleH'。
简而言之:
将二进制数(10000000 00000000 00000000)写入文件可以正常工作。
将相同的二进制数读入byte
数组结果为:
[0]00000000
[1]00000000
[2]10000000
由于strings
保持不变,因此阅读文件可能不是问题。
但是:将byte
数组解释回原始变量(long,double ...)会返回正确的结果。
因此,从我看来,变量的bytes
看起来的顺序错误。
这是真的吗?如果是这样,为什么会这样做,因为从我看来它似乎违反了IEEE 754(但它显然有效)?
如果我在这里遗漏任何东西,请纠正我,因为我在寻找这个问题的答案后仍然感到困惑......
答案 0 :(得分:2)
关于多字节结构中的顺序字节,没有通用的规则。
little-endian方法将四字节数0x01020304
按照0x04
,0x03
,0x02
,0x01
的顺序放入字节中。< / p>
big-endian方法会将相同的四字节数字按0x01
,0x02
,0x03
,0x04
的顺序放入字节中。
这些都不正确,但显然使用一种方法的系统需要一些转换才能与使用另一种方法的系统进行互操作。
(甚至有奇怪的组合,例如0x03
,0x04
,0x01
,0x02
或0x02
,0x01
,{{1} },0x04
但它们更为罕见,并且通常是由于将4字节值作为两个双字节值处理,采用大端方法进行排序,然后以小端方法处理它们,反之亦然。)
如果您正在使用.NET,您可能正在使用英特尔芯片或与之兼容的芯片,并且它们使用小端顺序将值存储在内存中。直接从内存复制到文件或返回将导致一个小端文件。
现在,字符串是一系列字符,其内存中表示是某种顺序的字节序列。因为&#34;你好&#34;我们将对0x03
进行某种表示,然后是H
,然后是e
,依此类推。
无论系统是小端还是大端,都是如此。
但是,如果其中一个字符的表示不是单字节,那么该表示可能会受到字节序的影响。
文件使用最常见的现代表示(实际上是99%的时间内唯一使用的表示)是UTF-8。 UTF-8将为代码点高于U + 007F的字符定义多字节序列,但该序列的顺序由UTF-8本身定义,因此不受字节顺序的影响。
第二个最常见的现代表现形式(如果你有充分的理由,剩下1%的时间使用的表现形式)是UTF-16。 UTF-16将字符作为16位单元处理,或者作为U + FFFF以上字符的两个16位单元处理。在使用两个16位单元的情况下,这些单元的顺序以UTF-16本身指定。但是,表示这些16位单元的两个八位字节的顺序没有在此级别指定,因此受字节顺序的影响。
因此,UTF-16可以用字节表示为UTF-16LE或UTF-16BE,或者在文件的开头用一个字节顺序标记表示,以便让读取软件确定哪个正在使用。因此,使用UTF-16&#34;你好&#34;可能是:
l
或者可能是:
0x00 0x68 0x00 0x65 0x00 0x6C 0x00 0x6C 0x00 0x6F