2012-12-20 9 views
13

注:私は誤っておおよそstatic_castを尋ねました。これは、最初に回答がstatic_castと記載されている理由です。floatする整数を再解析しても安全ですか?

リトルエンディアンの浮動小数点値を持つバイナリファイルがあります。私はそれらを機械に依存しない方法で読みたいと思う。私のバイトスワップルーチン(SDLから)は、符号なし整数型で動作します。

intとfloatの間を単純にキャストするのは安全ですか?

float read_float() { 
    // Read in 4 bytes. 
    Uint32 val; 
    fread(&val, 4, 1, fp); 
    // Swap the bytes to little-endian if necessary. 
    val = SDL_SwapLE32(val); 
    // Return as a float 
    return reinterpret_cast<float &>(val); //XXX Is this safe? 
} 

私はこのソフトウェアをできるだけポータブルにします。

+2

ポインタ型または参照型に対してのみ 'reinterpret_cast'を実行できます。投稿したコードはコンパイルされません。 – Praetorian

+1

おそらくfloat result = reintrepret_cast (val)のようなものです。 –

+0

私は本当に最初にコンパイルしようとしていたはずです:/ – QuasarDonkey

答えて

24

まあ、static_castは「安全」であり、動作を定義していますが、これはおそらく必要なものではありません。整数値を浮動小数点型に変換すると、単純に目標浮動小数点型で同じ整数値を表現しようとします。私。 int5float5.0になります(正確に表現可能であると仮定します)。

float値のオブジェクト表現を、Uint32という変数で宣言されたメモリに組み込んでいるようです。結果をfloatの値にするには、にメモリを再解釈する必要があります。タイプ-punningのこの種は、以下のコンパイラでの動作が保証されていないが、これは、あなたが好む場合reinterpret_cast

assert(sizeof(float) == sizeof val); 
return reinterpret_cast<float &>(val); 

または、同じことのポインタバージョン

assert(sizeof(float) == sizeof val); 
return *reinterpret_cast<float *>(&val); 

によって達成されるであろう厳密なエイリアシングのセマンティクス。もう1つの方法はこれを行うことです。

float f; 

assert(sizeof f == sizeof val); 
memcpy(&f, &val, sizeof f); 

return f; 

または、よく知られているユニオンハックを使用してメモリの再解釈を実装できます。厳格なエイリアシングの意味を持ついくつかのコンパイラは、タイプpunning

要するに
assert(sizeof(float) == sizeof(Uint32)); 

union { 
    Uint32 val; 
    float f; 
} u = { val }; 

return u.f; 
+0

謝罪、あなたは正しいです(私はreinterpret_cast、static_castを意味しました)。私はこれを反映するために質問を更新しました。 – QuasarDonkey

+0

ありがとうございます。私は「型打ち」という言葉を知らなかった。それはいくつかの有益な情報をもたらしました。私が読んだことに基づいて、私は* union * trickと一緒に行くだろうと思うが、それは十分サポートされているようだ。 – QuasarDonkey

+0

void * firstにキャストしてから*を浮動させて4の乗算の過去を取得するとどうなりますか?それは安全ですか? –

2

の公式にサポートされている方法として、労働組合ベースのアプローチを予約し、それは正しくないです。浮動小数点型に整数をキャストしていると、コンパイラはその整数を整数として解釈します。上記の統合ソリューションが機能します。

組合との事と同じ種類のを行う別の方法は、これを使用することですです:

return *reinterpret_cast<float*>(&val); 

これは、上記組合ソリューションとして、安全でない/平等に安全である、と私は間違いなく主張することをお勧めしますfloatがintと同じサイズであることを確認してください。

IEEE-754またはIEEE-854と互換性のない浮動小数点フォーマットがあることも警告します(これらの2つの規格は浮動小数点数と同じフォーマットですが、詳細の違いは何であるかはわかりません)。正直である)。したがって、異なる浮動小数点フォーマットを使用するコンピュータを使用している場合、それは転倒します。浮動小数点数の期待値と一緒にどこか離れた場所に格納されたバイトの缶詰のセットを除いて、それをチェックする方法があるかどうかわからないので、値を変換して "正しい"かどうかを確認してください。

+0

さて、私は今、型打ちに関するwikiの記事を読んできました。 「多くの一般的なプラットフォームでは、異なるポインターがマシン固有の方法で整列されていると、ポインター・パニングを使用すると問題が生じる可能性があります。このエイリアシングの問題は、共用体を使用することで解決できます。 – QuasarDonkey

+0

データ型のアライメントが異なる場合、整数から読み取られたデータがfloatと重なっていることが保証されていないため、組合にも問題がある可能性があります。しかし、私は2の整列でアドレスXに整数を置いて、浮動小数点数を4バイトに整列させて、クラッシュしたり、ひどく振る舞うことができると思うコンパイラを持つことができると思います。 ベストおそらく浮動小数点データをテキストとして、または整数形式の固定小数点として格納することです。そうすれば、それが何を意味するのか、またはアライメントについて疑う余地はありません。 –

+0

これは理にかなっていますが、バイナリの最適なオプションのように見えるので、私は組合に固執すると思います。残念ながら、私はレガシーシステムからファイルをサポートしているので、テキストを使用することはできません。 – QuasarDonkey

関連する問題