2017-11-01 3 views
2

私はストリームAPIを書いています。BigEndian/LittleEndianやunsigned vs signed変換を扱う必要がある多くのものを使用しています。私は動作する次のコードを持っています。しかし、私はそれが何をしているか知りたい、いくつかのELI5(私は5のように説明してください)できますか?安全ではない変換を浮動小数点数にするには、*(浮動小数点数)(&num)は何ですか?

int num = ReadInt(); 
return *(float*) (&num); 

public int ReadInt() 
     { 
      return 
       (_memoryStream.ReadByte() << 0x18) | 
       (_memoryStream.ReadByte() << 0x10) | 
       (_memoryStream.ReadByte() << 0x08) | 
       _memoryStream.ReadByte(); 
     } 

ここで、私はReadIntと同じように、LittleEndianをBigEndianに変えています。私の頭を包み込むことができない部分は、*(float*)(&num)です。

何らかのメモリシフトを行っていると推測していますが、それは100%ではありません。

答えて

2

&num - "numのアドレス" - 整数へのポインタです。

(float*)&num - "numのアドレスをfloatへのポインタに変換しました。"

これはメモリアドレスnumですが、コンパイラはその内容を整数ではなく浮動小数点数として解釈します。

*(float*)&num

- の含有量「numのアドレスは、フロートへのポインタに変換」 - つまり、numによって占められるメモリを取り、浮動小数点数としてそれを読み出します。だから、

あなたはバイトの0x40、0x10の中で読んした場合、0x00で、0x00に、 あなたはメモリ位置に整数0x40100000 = 1074790400を取得したい「NUM」 「NUM」のアドレスはに変換されます浮動小数点へのポインタ、そして あなたはその内容を取得します。定数0x40100000は、 を浮動小数点として解釈すると2.25であり、返されます。

+0

場合。この手法では危険性は、たとえば、明らかにあり私は最終的にこれらを安全に書き直す方法を模索するつもりですが、今はすべてのユニットテストが合格しており、何をしているのか分かります。ありがとうございました! – emalamisura

+0

さらに調べると、.NET用のBitConverterクラスに組み込まれているのと同じことが行われているようです。 https://referencesource.microsoft.com/#mscorlib/system/bitconverter.cs,8640d8adfffb155b – emalamisura

1

ただ、それはステップバイステップで説明する:

  1. &numに含まれるオブジェクトへのポインタを取得します。
  2. (float *)は、このポインタをfloatポインタにキャストします。
  3. *は、このポインタの参照を解除します。つまり、このポインタの値を取得します。

全体として、これはバイトストリーム内の4つの最新のバイトをfloatとして返します。しかし、おそらくこれはコーディングの最善の方法ではないかもしれません。

らしいをハザードした場合、これは望ましい動作ではないかもしれないintfloatとの間の直接的な変換はバイトの表現がpreserve the valueで読み取られることになるのではなくので、それがあった方法で、書かれていました。

2

ReadIntは、BigEndianの順序付けされたバイトのストリームから4バイトをintの4バイトにそれぞれ24ビット、16ビット、8ビット、および0ずつシフトすることでロードしますC,int,.Netなどは、プラットフォームに関係なく4バイトであることが保証されます)。

あなたが推測したように、これは独自のバイナリシリアル化形式を使用する「エンディアンに依存しない」ライブラリの一部です。対応するバイトオーダーのストリームに同様に4バイトのintを保存する対応するSaveIntメソッドがほぼ確実に存在します。

その他既に説明したコードという:

int num = ReadInt(); 
return *(float*) (&num); 

再解釈格納される単精度浮動小数点数として(メモリに格納されている)と仮定32ビットintの最初の4つのバイトを、 IEEE 754形式のフロートレイアウトhereなどです。使用される手法は、代わりにfloatへのポインタとしてポインタをintのアドレスに再キャストし、その値を反映させることです。

  • 8ビット指数
  • 23ビットが
  • を仮数ビット記号:重要なことに、 floatも.NETで4バイト(我々が読んだ intと同じサイズ)に格納され

なぜですか?フロートするint型から直接キャスト:

int num = ReadInt(); 
return (float)num; 

だろう代わりに、元の「フロート」を復元するには、代わりに4バイトのint型の整数値を保持するだろう、4バイトにシリアライズ。

あなたは、このコードは、ライブラリから来ていると言うので、ReadIntは、他の変換に使用されるユーティリティメソッドである可能性が高い - 4つのバイトを消費すなわち、他のタイプも、おそらく同様のポスト読んでくださいReadIntメソッドを使用することができます「再解釈」読み込まれたバイトのうちの

返さint占めるバイト数がまあ、それはかなり実際に巧妙なおかしくなり例えば、より大きなデータ型を満たすには不十分である。:

int num = ReadInt(); 
return *(double*) (&num); // Oops. 
関連する問題