25

注:最初に間違って尋ねまし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?
}

私は、このソフトウェアを可能な限りポータブルにしたいと考えています。

4

2 に答える 2

37

まあ、static_cast「安全」であり、動作が定義されていますが、これはおそらく必要なものではありません。整数値を float 型に変換すると、ターゲットの浮動小数点型で同じ整数値を表現しようとするだけです。すなわち5of 型はof型intに変わります(正確に表現できると仮定します)。5.0float

あなたがしているように見えるのは、変数floatとして宣言されたメモリの一部に値のオブジェクト表現を構築することです。Uint32結果の値を生成するには、そのメモリを再解釈floatする必要があります。これは、reinterpret_cast

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

または、必要に応じて、同じもののポインター バージョン

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

ただし、この種の型パニングは、厳密なエイリアシング セマンティクスに従うコンパイラで機能することが保証されていません。別のアプローチはこれを行うことです

float f;

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

return f;

または、よく知られているユニオン ハックを使用して、メモリの再解釈を実装できる場合もあります。これは、C++ では正式に違法です (未定義の動作)。つまり、このメソッドは、拡張機能としてサポートする特定の実装でのみ使用できます。

assert(sizeof(float) == sizeof(Uint32));

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

return u.f;
于 2012-12-20T23:55:55.083 に答える
4

要するに、それは正しくありません。整数をfloatにキャストすると、コンパイラーによってその時点で整数として解釈されます。上記のユニオンソリューションは機能します。

ユニオンと同じ種類のことを行う別の方法は、これを使用することです。

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

上記のユニオンソリューションと同様に安全/安全ではありません。floatがintと同じサイズであることを確認するためにassertを使用することを強くお勧めします。

また、IEEE-754またはIEEE-854と互換性のない浮動小数点形式があることも警告します(これら2つの標準は、浮動小数点数の形式が同じです。正直なところ、詳細の違いが何であるかは完全にはわかりません)。したがって、別の浮動小数点形式を使用するコンピューターを使用している場合は、フォールオーバーします。それをチェックする方法があるかどうかはわかりませんが、floatの期待値とともに、定型化されたバイトセットをどこかに格納してから、値を変換して「正しく」表示されるかどうかを確認します。

于 2012-12-21T00:11:36.943 に答える