2

以下问题让我很困惑:

我正在试验如何doubles,尤其是它们的“特殊”值,例如PositiveInfinity存储在文件中,这没问题。我通过三个简单的步骤完成了这项工作double:将其写入文件;将文件读入byte-array。这很容易,现在我知道Double.NaN二进制格式的 a 是什么样子了 :)

但后来我遇到了以下情况:

根据.Net-Framework,有一个NegativeZero

internal static double NegativeZero = BitConverter.Int64BitsToDouble(unchecked((long)0x8000000000000000));

它的表示方式非常简单(遵循 IEEE 754):

代表一个二进制数:long10000000...

第一个位表示double是负数。因此,代表 的NegativeZero- 0 * 2^0尾数和指数都是0

表示“正常” 0 将是 64 位全部设置为0.


但问题是将这些数字读入byte数组。我的假设是NegativeZero128 0 0... [二进制:100000 ...]

但实际上它是错误的方式:0 0...... 128![二进制:00000...0 10000000]

我的第一个想法是:“可能File.ReadAllBytes()以错误的顺序返回所有东西(这会很尴尬)”。所以我决定用一个string(->用一个字符串创建一个文件;将它读入byte数组)来测试阅读器

结果很好:byte数组中的“Hello”仍然是“Hello”,而不是上面的示例中提出的“olleH”。


再次简而言之:

将二进制数(10000000 00000000 00000000)写入文件可以正常工作。

将相同的二进制数读入byte数组结果是:

[0]00000000 [1]00000000 [2]10000000

读取文件不会是问题,因为strings保持不变。

但是:将byte数组解释回原始变量(long,double ...)会返回正确的结果。

因此,从我看来,bytes变量的存储顺序错误。

这是真的?如果是这样,为什么要这样做,因为在我看来它似乎违反了 IEEE 754(但它显然有效)?

如果我在这里遗漏任何东西,请纠正我,因为经过数小时搜索此问题的答案后我仍然感到困惑......

4

1 回答 1

2

关于多字节结构中的字节顺序没有通用规则。

little-endian 方法会将四字节数按, , ,0x01020304的顺序放入字节中。0x040x030x020x01

big-endian 方法会将相同的四字节数字按0x01, 0x02, 0x03,的顺序放入字节中0x04

这些都不是正确的,但显然使用一种方法的系统需要一些转换才能与使用另一种方法的系统互操作。

(甚至还有一些奇怪的组合,例如0x03, 0x04, 0x01, 0x02or 0x02, 0x01, 0x040x03但它们更罕见,并且通常是由于某些东西将 4 字节值视为两个 2 字节值,采用大端序方法进行排序,然后处理这些值在小端方法中,反之亦然)。

如果您正在使用 .NET,您可能使用的是 Intel 芯片或与之兼容的芯片,并且它们使用 little-endian 顺序将值存储在内存中。直接从内存复制到文件或返回将产生一个 little-endian 文件。

现在,字符串是一个字符序列,它在内存中的表示是按某种顺序排列的字节序列。因此,对于“Hello”,我们将有某种形式的表示,H后跟紧随e其后l,依此类推。

无论系统是 little-endian 还是 big-endian,都会出现这种情况。

但是,如果其中一个字符的表示不是单字节,则该表示可能会受到字节序的影响。

文件使用的最常见的现代表示形式(实际上是 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,“hello”可能是:

0x00 0x68 0x00 0x65 0x00 0x6C 0x00 0x6C 0x00 0x6F

或者它可能是:

0x68 0x00 0x65 0x00 0x6C 0x00 0x6C 0x00 0x6F 0x00
于 2015-05-13T09:57:19.107 回答