【问题标题】:What does i = * ( long * ) &y; do? [duplicate]i = * ( long * ) &y; 是什么?做? [复制]
【发布时间】:2017-12-22 19:56:09
【问题描述】:

我看到了下面的代码here

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the heck? 
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

下面这行我不明白。

i  = * ( long * ) &y; 

一般情况下,*& 都与指针一起使用,但这里都与变量一起使用。那么,它在这里做什么呢?

【问题讨论】:

  • 将浮点数转换为长整数的疯狂方法?
  • 这不是快速平方根算法。是的。
  • float x2, y;... i = * ( long * ) &y; 是未定义的行为。使用union
  • @chux 我认为这段代码早于严格别名规则。
  • @DanielH 我同意你的“这是我看到的唯一 UB”。然而,我们正在冒险 OT。

标签: c


【解决方案1】:

该行正在获取float,查看拥有float 的内存,将该内存重新解释为拥有long 的内存,然后得到long。基本上,它将浮点数的位模式重新解释为整数的位模式,以便弄乱它的位。

很遗憾,该代码也是错误。由于here 中描述的原因,您不能取消引用该强制转换的指针。在 C 中,重新解释位模式的唯一方法是通过memcpy。 (根据 C 变体和实现,通过联合可能也是可以接受的。)

【讨论】:

  • 你能快速解释一下 memcopy 和直接进行转换(不是通过寻址)之间的主要区别吗?
  • @kabanus 你说的“马上做演员表”是什么意思?
  • 我的意思是i=(long)y
  • @kabanus 不同之处在于,在(long)y 中,正在转换一个数字。在 OP 的情况下,正在转换 内存地址。你是在告诉编译器“你知道那个内存地址吗?假装那里的数据是一个整数,而不是一个浮点数”。当然它不是真的,所以你得到的价值将与浮点数的表示方式一样多,因为它与所讨论的数字实际有关。
  • @DanielH C99 确实如此,但 C89 对此持谨慎态度。
【解决方案2】:

首先,免责声明:这是技术上未定义的行为,因为它违反了strict aliasing rule,但大多数编译器会执行以下操作,我不知道第一次编写时的标准情况。

当你看表达式时,主要有四个部分:(

  1. y 是我们要转换的浮点变量。很简单。
  2. & 是常用的地址运算符,所以&y 是指向y 的指针。
  3. (long *) 是指向 long 指针的强制转换,因此 (long *) &y 是指向与 y 相同的内存位置的指针。那里没有真正的long,只有float,但如果floatlong 都是32 位(如代码假定的那样),这将为您提供指向具有相同位的long 的指针模式为float
  4. 最后,* 取消引用指针。因此,完整的表达式* ( long * ) &y; 为您提供了一个与y 具有相同位模式的long

通常,与float 具有相同位模式的long 是没有用的,因为它们以完全不同的方式存储数字。但是,对long 进行位操作更容易,程序稍后会将其转换回 `float。

【讨论】:

    【解决方案3】:

    这意味着y(使其成为指针)的地址转换为long指针,取消引用并分配给i

    【讨论】:

    • There isn't really a spiral rule. 在这种特殊情况下也没有螺旋。
    • 为了澄清@OliverCharlesworth 的评论,螺旋规则是实际 C++ 类型解析规则的简化。由于它是一种简化,因此螺旋规则给出错误答案的情况很多。无论如何,它只用于解析类型,而不是表达式。
    猜你喜欢
    • 2017-05-06
    • 2016-06-12
    • 2015-06-17
    • 2015-08-17
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    • 2013-02-17
    • 2021-11-03
    相关资源
    最近更新 更多