2

次の問題は私を大いに混乱させました:

doubles私はどのように、特にそれらの「特別な」値PositiveInfinityがファイルに保存されるかを実験していましたが、問題はありませんでした。これは 3 つの簡単な手順で行いましたdouble。ファイルに書き込みます。ファイルを配列に読み込みますbyte。これは非常に簡単Double.NaNで、バイナリ形式で a がどのように見えるかがわかりました:)

しかし、私は次のことに出くわしました:

.Net-Framework によると、次のものがありますNegativeZero

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

表現方法は非常に単純です (IEEE 754 に従っています)。

long2 進数を表します: 10000000...

最初のビットは、doubleが負であることを示しています。したがって、仮数部と指数部が両方とも であるため、NegativeZeroを表すために起こることは.- 0 * 2^00

「通常の」0 を表すと、64 ビットがすべて に設定され0ます。


しかし問題は、これらの数値をbyte配列に読み込むことです。私が想定したのは、次のとおりですNegativeZero: 128 0 0... [バイナリ: 100000 ...]

しかし、実際にはそれは間違った方法でした: 0 0... 128! [バイナリ: 00000...0 10000000]

私が最初に考えたのは、「File.ReadAllBytes()すべてが間違った順序で返される可能性がある (これは厄介なことです)」ということでした。そこで、リーダーをテストすることにしましたstring(->文字列を含むファイルを作成し、それをbyte配列に読み込みます)

結果は問題ありませんでした: 'Hello' はbyte配列内の 'Hello' のままであり、上記の提案された 'olleH' の例とは異なります。


繰り返しになりますが、一言で言えば:

ファイルへの 2 進数 (10000000 00000000 00000000) の書き込みは正常に機能します。

同じ 2 進数をbyte配列に読み込むと、次のようになります。

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

ファイルの読み取りはstrings同じままであるため、問題になることはありません。

BUT:byte配列を解釈して元の変数 (long、double...) に戻すと、正しい結果が返されます。

bytesしたがって、私の見解では、変数の が間違った順序で格納されているように見えます。

これは本当ですか?もしそうなら、私の見解ではIEEE 754に違反しているように見えるので(しかし、それは明らかに機能します)、なぜこのように行われるのですか?

そして、この問題に対する答えを何時間も検索した後もまだ混乱しているため、ここに何かが欠けている場合は修正してください...

4

1 に答える 1

2

マルチバイト構造内のバイトの順序について、普遍的なルールはありません。

リトルエンディアンのアプローチでは、4 バイトの数値が, , ,0x01020304の順にバイトに入れられます。0x040x030x020x01

ビッグエンディアンのアプローチでは、同じ 4 バイトの数値が0x01, 0x02, 0x03,の順にバイトに入れられます0x04

これらはどちらも正しくも正しくもありませんが、一方のアプローチを使用するシステムが他方のアプローチを使用するシステムと相互運用するには、何らかの変換が必要であることは明らかです。

0x03( 、、、0x040x010x02などの奇妙な組み合わせもありますが、それらははるかにまれであり、一般に、4 バイト値を 2 つの 2 バイト値として処理し、ビッグエンディアン方式で順序付けを行い、それらを処理するために発生します。リトルエンディアンのアプローチ、またはその逆)。0x020x010x040x03

.NET を使用している場合は、おそらく Intel チップまたはそれと互換性のあるチップを使用しており、メモリに値を格納するためにリトルエンディアン順序を使用しています。メモリからファイルへ、またはその逆に直接コピーすると、リトル エンディアン ファイルになります。

現在、文字列は一連の文字であり、そのメモリ内表現はある順序の一連のバイトです。このように、"Hello" の場合、何らかの形で、H後に続くなどの表現が得eられlます。

これは、システムがリトルエンディアンであろうとビッグエンディアンであろうと当てはまります。

ただし、これらの文字のいずれかの表現がシングルバイトでない場合、その表現はエンディアンの影響を受ける可能性があります。

ファイルの使用に関する最も一般的な最新の表現 (そして実際に 99% の時間で使用される唯一のもの) は UTF-8 です。UTF-8 は、U+007F を超えるコード ポイントを持つ文字のマルチバイト シーケンスを定義しますが、そのシーケンスの順序は UTF-8 自体によって定義されるため、エンディアンの影響を受けません。

2 番目に一般的な最新の表現 (および、正当な理由があれば残りの 1% の時間に使用する表現) は UTF-16 です。UTF-16 は、文字を 16 ビット単位、または U+FFFF を超える文字の場合は 2 つの 16 ビット単位として処理します。2 つの 16 ビット ユニットが使用されている場合、それらのユニットの順序は UTF-16 自体で指定されます。ただし、これらの 16 ビット単位を表す 2 つのオクテットの順序は、このレベルでは指定されていないため、エンディアンの影響を受けます。

したがって、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 に答える