这是否指针铸造打破严格走样规则?(Does this pointer casting break s

2019-08-19 14:42发布

这是从雷神之锤3的高速逆平方根实现:

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

我注意到,long int,而 i需要在地址解除引用的值(转换为long *浮动 y 。 然后,该代码执行对操作i存储在该地址处解除引用值(转换为前float *的) iy

这会打破严格走样规则,因为i是不是同一类型的y

我想,也许它并不因为价值被取消引用和复制 ; 所以操作都在一个副本,而不是原来的执行。

Answer 1:

Yes, this code is badly broken and invokes undefined behavior. In particular, notice these two lines:

    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking

Since the object *(long *)&y has type long, the compiler is free to assume it cannot alias an object of type float; thus, the compiler could reorder these two operations with respect to one another.

To fix it, a union should be used.



Answer 2:

是的,它打破别名规则。

在现代C,你可以改变i = * (long *) &y; 至:

i = (union { float f; long l; }) {y} .l;

y = * (float *) &i; 至:

y = (union { long l; float f; }) {i} .f;

只要你有保证的是,在C实现被使用, longfloat一种类型的对象的字节将被重新解释为另一种类型的:具有合适的尺寸和表示,则该行为由C标准定义。



Answer 3:

是的,它打破别名规则。

最干净的修复对于像i = * ( long * ) &y; 会是这样的:

  memcpy(&i, &y, sizeof(i)); // assuming sizeof(i) == sizeof(y)

它避免了对齐和走样的问题。 并启用了优化,调用memcpy()通常应该只有少数的指令所取代。

就像任何其他方法建议,这种方法不能解决与陷阱表示任何问题。 在大多数平台上,但是,也有在整数没有陷阱表示,如果你知道你的浮点格式就可以避免浮点格式陷阱表示,如果有任何。



Answer 4:

i = * ( long * ) &y;

This breaks aliasing rules and therefore invokes undefined behavior.

You are accessing object y with a type different than float, or a signed / unsigned variant of char.

y = * ( float * ) &i;

This statement above also breaks aliasing rules.



文章来源: Does this pointer casting break strict aliasing rule?