浮点位和严格的混叠 [英] float bits and strict aliasing

查看:245
本文介绍了浮点位和严格的混叠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从一个浮点抽取位,而不调用未定义的行为。这是我的第一次尝试:

  unsigned foo(float x)
{
unsigned * u = unsigned *)& x;
return * u;
}

根据我的理解,这不能保证由于严格的别名规则, 对?

 无符号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;无符号u; };
f = x;
return u;
}


$ b $ p

为了完整起见,下面是 foo 。还有未定义的行为,对吗?

 无符号的引数(float x)
{
return(unsigned&) X;
}

假设两者都是32位宽,当然)?






编辑:这里是 memcpy 版本。由于许多编译器不支持 static_assert ,我已经用一些模板元编程替换了 static_assert

 模板< bool,typename T> 
struct requirement;

template< typename T>
struct requirement< true,T>
{
typedef T type;
};

无符号位(float x)
{
需求< sizeof(unsigned)== sizeof(float),unsigned>
memcpy(& u,& x,sizeof u);
return u;
}


解决方案

避免任何问题是对memcpy。

  unsigned int FloatToInt(float f)
{
static_assert (float)== sizeof(unsigned int),Sizes must match);
unsigned int ret;
memcpy(& ret,& f,sizeof(float));
return ret;
}

因为你要记住一个固定的金额,编译器会优化它。 p>

这说明union方法受到广泛支持。


I am trying to extract the bits from a float without invoking undefined behavior. Here is my first attempt:

unsigned foo(float x)
{
    unsigned* u = (unsigned*)&x;
    return *u;
}

As I understand it, this is not guaranteed to work due to strict aliasing rules, right? Does it work if a take an intermediate step with a character pointer?

unsigned bar(float x)
{
    char* c = (char*)&x;
    unsigned* u = (unsigned*)c;
    return *u;
}

Or do I have to extract the individual bytes myself?

unsigned baz(float x)
{
    unsigned char* c = (unsigned char*)&x;
    return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
}

Of course this has the disadvantage of depending on endianness, but I could live with that.

The union hack is definitely undefined behavior, right?

unsigned uni(float x)
{
    union { float f; unsigned u; };
    f = x;
    return u;
}

Just for completeness, here is a reference version of foo. Also undefined behavior, right?

unsigned ref(float x)
{
    return (unsigned&)x;
}

So, is it possible to extract the bits from a float (assuming both are 32 bits wide, of course)?


EDIT: And here is the memcpy version as proposed by Goz. Since many compilers do not support static_assert yet, I have replaced static_assert with some template metaprogramming:

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;
}

解决方案

About the only way to truly avoid any issues is to memcpy.

unsigned int FloatToInt( float f )
{
   static_assert( sizeof( float ) == sizeof( unsigned int ), "Sizes must match" );
   unsigned int ret;
   memcpy( &ret, &f, sizeof( float ) );
   return ret;
}

Because you are memcpying a fixed amount the compiler will optimise it out.

That said the union method is VERY widely supported.

这篇关于浮点位和严格的混叠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆