2012-12-24 12 views
5

floatを長さ4のバイト配列(char *の配列)に変換する方法は?私はネットワーク上でいくつかのデータ、tcpを送る必要があり、バイト配列としてfloatを送る必要があります。 (私は2桁の10進数の精度を知っているので、クライアント側で100を掛け、サーバで100で割る - 基本的に整数に変換し、次に& 0xff < <操作でバイトを見つける)。しかし、それは醜いものであり、時間の間に精度を失う可能性があります。一連のバイトとしていかなるタイプを読むfloatを長さ4のバイト配列(char *の配列)に変換する方法は?

+0

精度を維持するには8バイトが必要だと思います。 –

+0

@HennoBrandsmaこれは一般的に「ダブル」です。最新のシステムでは、 'float'は4バイトのIEEE-754形式です。 –

+0

クライアント/サーバーを1つの形式(大/小)に制限しない限り、最終的なソリューションでエンディアンアカウンティングをディスカウントしないでください。 – WhozCraig

答えて

9

は非常に簡単です:

float f = 0.5f; 

unsigned char const * p = reinterpret_cast<unsigned char const *>(&f); 

for (std::size_t i = 0; i != sizeof(float); ++i) 
{ 
    std::printf("The byte #%zu is 0x%02X\n", i, p[i]); 
} 

執筆フロートへのネットワークストリームから同様に動作し、あなただけがconstを残したいです。

常に(任意char型が許容される)バイトのシーケンスとして任意のオブジェクトを再解釈することが許可され、この明示ないエイリアシング違反。任意の型のバイナリ表現はもちろんプラットフォームに依存するので、受信者が同じプラットフォームを持つ場合は、これを直列化にのみ使用してください。

+0

しかし、これはもちろん、ネットワークにバイトを書かなければならない場合は、彼を助けません。 –

+0

@JamesKanze:確かに 'write(fd、p、sizeof(float))'を使うことができます。質問は誰が*読むことができますか:-) –

+0

'write'が正しいとは事実上ありません。しかし、問題はネットワークを介して出力することでした。だから彼が書いているのは、彼が使っているプロトコルが定義しているフォーマットに対応していなければならない。 –

5

最初に行う必要があるのは、ネットワークプロトコルの フロートのフォーマットを判別することです。 IBMメインフレーム、Oracle Sparcおよび通常の PCはすべて4バイトの浮動小数点数を持っていますが、3種類の異なる フォーマットを持っています。フォーマットを知っていれば、 移植性の要件に応じて、2つの異なる戦略を使用できます。

プロトコルのフォーマットがIEEE(最も頻繁なケース)の場合、 である必要はありません をIEEEされていないマシンへの移植(WindowsおよびほとんどのUnixは、IEEE —ほとんどのメインフレームではないされている)、 あなたは uint32_tにフロートを変換するタイプpunningを使用することができますし、いずれかを使用して、出力:

std::ostream& 
output32BitUInt(std::ostream& dest, uint32_t value) 
{ 
    dest.put((value >> 24) & 0xFF); 
    dest.put((value >> 16) & 0xFF); 
    dest.put((value >> 8) & 0xFF); 
    dest.put((value  ) & 0xFF); 
} 

ビッグエンディアン(通常のネットワーク注文)、または:

std::ostream& 
output32BitUInt(std::ostream& dest, uint32_t value) 
{ 
    dest.put((value  ) & 0xFF); 
    dest.put((value >> 8) & 0xFF); 
    dest.put((value >> 16) & 0xFF); 
    dest.put((value >> 24) & 0xFF); 
} 

(いくつかのプロトコルで使用されます)。 を使用するプロトコルは、プロトコル用に定義された形式に依存します。

floatからuint32_tに変換するには、 コンパイラを確認する必要があります。 memcpyを使用するのは、 で完全に保証されている唯一の方法です。浮動小数点演算で reinterpret_cast<uint32_t&>を使用し、 のほとんどの(すべて?)コンパイラもunionを使用してサポートするということです。

あなたにもメインフレームに移植する必要があり、またはフォーマット がIEEE以外のものであれば、あなたはフロートから 指数、記号と仮数部を抽出する必要があります、と で出力各ターゲットフォーマット。次のような何かが(IEEEを使用しないメインフレームを 含む)任意のマシン上 出力IEEEビッグエンディアンに動作するはずですし、あなたにいくつかのアイデアを与える必要があります。

oxdrstream& 
oxdrstream::operator<<(
    float    source) 
{ 
    BytePutter   dest(*this) ; 
    bool    isNeg = source < 0 ; 
    if (isNeg) { 
     source = - source ; 
    } 
    int     exp ; 
    if (source == 0.0) { 
     exp = 0 ; 
    } else { 
     source = ldexp(frexp(source, &exp), 24) ; 
     exp += 126 ; 
    } 
    uint32_t    mant = source ; 
    dest.put((isNeg ? 0x80 : 0x00) | exp >> 1) ; 
    dest.put(((exp << 7) & 0x80) | ((mant >> 16) & 0x7F)) ; 
    dest.put(mant >> 8) ; 
    dest.put(mant  ) ; 
    return *this ; 
} 

BytePutterは単純なクラスです出力 の定型句を処理し、エラーチェックを行います)もちろん、 の出力がIEEE以外の場合は、出力の操作は異なりますが、これには基本原則が示されています。 (あなたがuint32_tをサポートしていない多くのエキゾチックなメインフレーム、 の一部への移植が必要な場合は、23ビットよりも大きい任意の 符号なし整数型に置き換えることができます。)

2

ちょうど1内のデータをオーバーレイエリア、in C

union dataUnion { 
    float f; 
    char fBuff[sizeof(float)]; 
} 
// to use: 
dataUnion myUnion; 
// 
myUnion.f = 3.24; 
for(int i=0;i<sizeof(float);i++) 
    fputc(myUnion.fbuff[i],fp); // or what ever stream output.... 
関連する問題