C#'unsafe'函数 – *(float *)(&result)vs(float)(result)

任何人都可以用简单的方式解释下面的代码:

public unsafe static float sample(){ int result = 154 + (153 << 8) + (25 << 16) + (64 << 24); return *(float*)(&result); //don't know what for... please explain } 

注意:上面的代码使用不安全的函数

对于上面的代码,我有困难的时候,因为我不明白它的返回值与下面的返回值之间的区别是什么:

 return (float)(result); 

如果返回*(float*)(&result)是否需要使用不安全的函数?

在.NET上, float使用32位存储的IEEE binary32单精度浮点数表示。 显然,代码通过将这些位组合成一个int构造这个数字,然后使用unsafe把它转换为一个float 。 转换是用C ++术语称为reinterpret_cast ,当执行转换时不进行转换 – 这些位只是被重新解释为新types。

IEEE单精度浮点数

组装的数字是hex的4019999A或二进制的01000000 00011001 10011001 10011010

  • 符号位是0(这是一个正数)。
  • 指数位是10000000 (或128),导致指数128-127 = 1(分数乘以2 ^ 1 = 2)。
  • 小数位是00110011001100110011010 ,如果没有别的,几乎有一个零和一个可识别的模式。

返回的浮点数与2.4转换为浮点数完全相同,整个函数可以简单地由文本2.4freplace。

最后的零这样的“打破了比特模式”的分数是否有可能使浮动匹配的东西,可以写入使用浮点文字?


那么普通演员和这个奇怪的“不安全演员”之间有什么区别呢?

假设下面的代码:

 int result = 0x4019999A // 1075419546 float normalCast = (float) result; float unsafeCast = *(float*) &result; // Only possible in an unsafe context 

第一个转换采用整数1075419546并将其转换为浮点表示,例如1075419546f 。 这包括计算将原始整数表示为浮点数所需的符号,指数和小数位。 这是一个不平凡的计算,必须完成。

第二个演员是更险恶(只能在不安全的情况下执行)。 &result&result地址返回一个指向存储整数1075419546的位置的指针。 指针解引用操作符*可以用来检索指针指向的值。 使用*&result将检索存储在该位置的整数,但是通过首先将指针转换为float* (指向float的指针),浮点数会从内存位置检索,导致浮点数2.4f被分配给unsafeCast 。 所以*(float*) &result的叙述给了我一个指向result的指针,并且假设指针是指向一个float指针,并且检索指针指向的值

与第一次演员相反,第二次演员不需要任何计算。 它只是将result存储的32位推送到unsafeCast (幸运的是32位)。

一般来说,执行这样的操作可能会在很多方面失败,但是通过使用unsafe方法,您告诉编译器,您知道自己在做什么。

如果我正在解释什么方法正在做,这是一个安全的等价物:

 public static float sample() { int result = 154 + (153 << 8) + (25 << 16) + (64 << 24); byte[] data = BitConverter.GetBytes(result); return BitConverter.ToSingle(data, 0); } 

正如已经说过的那样,它将int值重新解释为一个float

这看起来像是一个优化尝试。 而不是做浮点计算,你正在浮点数的整数表示上进行整数计算。

请记住,浮点数就像整数一样存储为二进制值。

计算完成后,您正在使用指针和铸造将整数转换为浮点值。

这与将值转换为浮点数不同。 这会将int值1变成浮点数1.0。 在这种情况下,将int值转换为存储在int中的二进制值描述的浮点数。

很难解释得很好。 我会寻找一个例子。 🙂

编辑:看这里: http : //en.wikipedia.org/wiki/Fast_inverse_square_root

你的代码基本上和本文所描述的一样。

回复:它在做什么?

它取int的字节值,而不是将这些字节解释为一个浮点数(没有转换)。

幸运的是,浮动和整数具有相同的4个字节的数据大小 。

因为Sarge Borsch问,这是“联盟”的等价物:

 [StructLayout(LayoutKind.Explicit)] struct ByteFloatUnion { [FieldOffset(0)] internal byte byte0; [FieldOffset(1)] internal byte byte1; [FieldOffset(2)] internal byte byte2; [FieldOffset(3)] internal byte byte3; [FieldOffset(0)] internal float single; } public static float sample() { ByteFloatUnion result; result.single = 0f; result.byte0 = 154; result.byte1 = 153; result.byte2 = 25; result.byte3 = 64; return result.single; } 

正如其他人已经描述的那样,它将int的字节看作是一个浮点数。

您可能会得到相同的结果,而不使用这样的不安全的代码:

 public static float sample() { int result = 154 + (153 << 8) + (25 << 16) + (64 << 24); return BitConverter.ToSingle(BitConverter.GetBytes(result), 0); } 

但是不会再那么快了,你不妨使用浮动/双打和math函数。