未定義の動作を呼び出さずに float からビットを抽出しようとしています。これが私の最初の試みです:
unsigned foo(float x)
{
unsigned* u = (unsigned*)&x;
return *u;
}
私が理解しているように、厳密なエイリアシング規則により、これが機能することは保証されていませんよね? 文字ポインターを使用して中間ステップを実行すると機能しますか?
unsigned bar(float x)
{
char* c = (char*)&x;
unsigned* u = (unsigned*)c;
return *u;
}
または、個々のバイトを自分で抽出する必要がありますか?
unsigned baz(float x)
{
unsigned char* c = (unsigned char*)&x;
return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
}
もちろん、これにはエンディアンに依存するという欠点がありますが、私はそれを受け入れることができました.
ユニオンハックは間違いなく未定義の動作ですよね?
unsigned uni(float x)
{
union { float f; unsigned u; };
f = x;
return u;
}
完全を期すために、ここに の参照バージョンを示しfoo
ます。また、未定義の動作ですよね?
unsigned ref(float x)
{
return (unsigned&)x;
}
それで、フロートからビットを抽出することは可能ですか(もちろん、両方が32ビット幅であると仮定します)?
編集: そして、これmemcpy
が Goz によって提案されたバージョンです。多くのコンパイラはまだサポートしていないため、いくつかのテンプレート メタプログラミングstatic_assert
に置き換えました。static_assert
template <bool, typename T>
struct requirement;
template <typename T>
struct requirement<true, T>
{
typedef T type;
};
unsigned bits(float x)
{
requirement<sizeof(unsigned)==sizeof(float), unsigned>::type u;
memcpy(&u, &x, sizeof u);
return u;
}