我正在编写一个流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%。
答案 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
大小相同):
为什么呢?从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)
只是一步一步解释:
asio::ip::tcp::resolver
获取指向&
。num
将此指针强制转换为浮点指针。(float *)
取消引用此指针,即获取此指针的值。总的来说,这会将字节流中最近的四个字节作为float返回。虽然,你可能会说,这可能不是编码的最好方法。
如果我冒险猜测,这是按原样编写的,因为*
和int
之间的直接转换会preserve the value而不是字节的表示形式读入,这可能不是理想的行为。