在 .NET 上,a使用 32 位存储float
的IEEE binary32单精度浮点数表示。显然,代码通过将位组装成 anint
然后将其转换为float
using 来构造这个数字unsafe
。转换在 C++ 术语中称为 a reinterpret_cast
,在执行转换时不进行任何转换——这些位只是被重新解释为一种新类型。
组装的数字是4019999A
十六进制或01000000 00011001 10011001 10011010
二进制:
- 符号位为 0(它是一个正数)。
- 指数位是
10000000
(或 128)导致指数 128 - 127 = 1(分数乘以 2^1 = 2)。
- 如果没有别的,小数位
00110011001100110011010
几乎具有可识别的零和一模式。
返回的 float 具有与 2.4 转换为浮点的完全相同的位,整个函数可以简单地替换为 literal 2.4f
。
分数的“破坏位模式”的最后一个零可能是为了使浮点匹配可以使用浮点文字编写的东西?
那么常规演员表和这种奇怪的“不安全演员表”有什么区别?
假设以下代码:
int result = 0x4019999A // 1075419546
float normalCast = (float) result;
float unsafeCast = *(float*) &result; // Only possible in an unsafe context
第一次转换采用整数1075419546
并将其转换为浮点表示,例如1075419546f
. 这涉及计算将原始整数表示为浮点数所需的符号、指数和小数位。这是一个必须完成的重要计算。
第二个演员更险恶(只能在不安全的情况下执行)。&result
获取返回指向整数存储result
位置的指针的地址。然后可以使用1075419546
指针解引用运算符来检索指针指向的值。*
Using*&result
将检索存储在该位置的整数,但是首先将指针转换为 a float*
(指向 a 的指针float
),而是从内存位置检索浮点数,从而将浮点数2.4f
分配给unsafeCast
. 所以叙述*(float*) &result
是给我一个指针result
并假设指针是指向 a 的指针float
并检索指针指向的值。
与第一次演员相比,第二次演员不需要任何计算。它只是将存储的 32 位推result
入unsafeCast
(幸运的是也是 32 位)。
一般来说,执行这样的强制转换可能会在很多方面失败,但通过使用unsafe
你告诉编译器你知道你在做什么。