在int中浮动不安全转换,*(float *)(& num)做什么?

时间:2017-11-01 04:46:54

标签: c# unsafe

我正在编写一个流API,它使用了很多东西来处理BigEndian / LittleEndian以及无符号vs签名转换。我有以下代码,它确实有效。但是我想知道它在做什么,可以用一些ELI5(像我这样解释)吗?

int num = ReadInt();
return *(float*) (&num);

 public int ReadInt()
        {
            return 
                (_memoryStream.ReadByte() << 0x18) |
                (_memoryStream.ReadByte() << 0x10) |
                (_memoryStream.ReadByte() << 0x08) |
                _memoryStream.ReadByte();
        }

现在我得到了ReadInt的功能,它只是将LittleEndian变成了BigEndian。我似乎无法绕过的部分是*(float*)(&num)

我猜它会做某种内存转移,但不是100%。

3 个答案:

答案 0 :(得分:2)

&num - “num的地址”,是指向整数的指针。

(float*)&num - “num的地址,转换为浮动指针。”

这是num的内存地址,但编译器会将其内容解释为浮点数,而不是整数。

*(float*)&num - “num地址的内容,转换为指向浮动的指针” - 换句话说,占用num占用的内存并将其读取为浮点数。

所以如果你要读取字节0x40,0x10,0x00,0x00, 你在内存位置'num'得到整数0x40100000 = 1074790400 'num'的地址将转换为指向float的指针,并且 你会把它的内容拉出来。解释时常量0x40100000 作为一个浮点数,是2.25,这是你将返回的。

答案 1 :(得分:2)

假设这是不安全的C#代码,ReadInt通过将每个字节移位24位,16位,8位,将BigEndian有序字节流中的4个字节加载到int的4个字节中,和0分别(与C等语言不同,int中的.Net保证为4个字节,与平台无关。)

正如您所猜测的,这可能是使用其自己专有的二进制序列化格式的'无限期'库的一部分。几乎可以肯定会有一个相应的SaveInt方法,它同样会以相应的字节顺序将4字节的int保存到流中。

其他人已经解释过,代码:

int num = ReadInt();
return *(float*) (&num);

重新解释假定的32位int的前4个字节(存储在内存中),作为单精度浮点数,存储为IEEE 754格式浮动布局here。使用的技术是将指向int的地址的指针重新转换为指向float的指针,然后取消该值。

重要的是,float也存储在4.Net中的4个字节中(与我们读过的int大小相同):

  • 1位符号
  • 8位指数
  • 23位尾数

为什么呢?从int到float的直接转换:

int num = ReadInt();
return (float)num;

将代替恢复序列化为4个字节的原始“float”,而不是保留4个字节int的整数值。

由于您说此代码来自库,因此ReadInt可能是其他转换中使用的实用方法 - 即消耗4个字节的其他类型也可能使用ReadInt方法对读取的字节进行类似的后读“重新解释”。

这种技术显然存在危险,例如,如果返回的int占用的字节数不足以满足更大的数据类型,例如:

int num = ReadInt();
return *(double*) (&num); // Oops.

答案 2 :(得分:1)

只是一步一步解释:

  1. asio::ip::tcp::resolver获取指向&
  2. 中包含的对象的指针
  3. num将此指针强制转换为浮点指针。
  4. (float *)取消引用此指针,即获取此指针的值。
  5. 总的来说,这会将字节流中最近的四个字节作为float返回。虽然,你可能会说,这可能不是编码的最好方法。

    如果我冒险猜测,这是按原样编写的,因为*int之间的直接转换会preserve the value而不是字节的表示形式读入,这可能不是理想的行为。