C# 在int到float的不安全转换中,什么';s是*(float*)(&;num)吗?
我正在编写一个流API,它使用了很多东西来处理BigEndian/LittleEndian和无符号与有符号的转换。我有下面的代码,它可以工作。但是我想知道它在做什么,能不能请一些ELI5(像我一样解释一下)C# 在int到float的不安全转换中,什么';s是*(float*)(&;num)吗?,c#,unsafe,C#,Unsafe,我正在编写一个流API,它使用了很多东西来处理BigEndian/LittleEndian和无符号与有符号的转换。我有下面的代码,它可以工作。但是我想知道它在做什么,能不能请一些ELI5(像我一样解释一下) int num=ReadInt(); 返回*(浮点*)(&num); 公共int ReadInt() { 返回 (_memoryStream.ReadByte()只是一步一步地解释一下: &获取指向num中包含的对象的指针 (float*)将此指针强制转换为浮点指针 *取消引用此指针,即获取
int num=ReadInt();
返回*(浮点*)(&num);
公共int ReadInt()
{
返回
(_memoryStream.ReadByte()只是一步一步地解释一下:
&
获取指向num
中包含的对象的指针
(float*)
将此指针强制转换为浮点指针
*
取消引用此指针,即获取此指针处的值
总的来说,这将以浮点形式返回字节流中最近的四个字节
如果我冒险猜测一下,这是这样写的,因为int
和float
之间的直接转换,而不是读取字节的表示,这可能不是期望的行为。&num
--“num
的地址”,它是指向整数的指针
(float*)&num
-“num的地址,转换为指向float的指针。”
这是num
的内存地址,但编译器将其内容解释为浮点数,而不是整数
*(float*)&num
“num
的地址”的内容,转换为指向float的指针-换句话说,获取num
占用的内存,并将其作为浮点数读取
因此,如果要读入字节0x40、0x10、0x00、0x00,
您将在内存位置“num”中获得整数0x40100000=1074790400
“num”的地址将转换为指向float的指针,并且
你可以提取它的内容。当解释时,常量0x40100000
作为一个浮点数,是2.25,这是您将返回的。假设这是不安全的C#code,
ReadInt
通过将每个字节分别移位24位、16位、8位和0,将4个字节从BigEndian顺序字节流加载到int
的4个字节中(与C
等语言不同,.Net
中的int
保证为4字节,与平台无关)
正如您所猜测的,这可能是“endian不可知”库的一部分,该库使用其专有的二进制序列化格式。几乎可以肯定会有一个相应的SaveInt
方法,该方法同样会将一个4字节的int按相应的字节顺序保存到流中
其他人已经解释过,代码:
int num = ReadInt();
return *(float*) (&num);
将假定的32位int
(存储在内存中)的前4个字节重新解释为单精度浮点,存储为IEEE 754格式浮点布局。使用的技术是将指向int地址的指针重新转换为指向浮点的指针,然后取消该值
重要的是,float
也存储在.Net中的4个字节中(与我们读到的int
大小相同):
- 1位符号
- 8位指数
- 23位尾数
int num = ReadInt();
return (float)num;
将不会恢复序列化为4字节的原始“float”,而是保留4字节int的整数值
由于您说此代码来自库,因此ReadInt
很可能也是其他转换中使用的实用方法-即,消耗4字节的其他类型也可以使用ReadInt
方法对读取的字节进行类似的读后“重新解释”
这种技术显然存在危险,例如,如果返回的int
占用的字节数不足以满足更大的数据类型,例如:
int num = ReadInt();
return *(double*) (&num); // Oops.
好吧,这真是太聪明了。我最终会探索如何重写它们以确保安全,但现在我所有的单元测试都通过了,我知道它在做什么。谢谢!进一步检查后,用于.NET的内置类BitConverter似乎也在做同样的事情。
int num = ReadInt();
return *(double*) (&num); // Oops.