我最近喜欢阅读Beej的《网络编程指南》。在7.4节中,他讨论了与发送彩车有关的问题。他提供了一个简单(幼稚)的解决方案,其中他通过将浮点数转换为来“打包”浮点数uint32_t
:
uint32_t htonf(float f)
{
uint32_t p;
uint32_t sign;
if (f < 0) { sign = 1; f = -f; }
else { sign = 0; }
p = ((((uint32_t)f)&0x7fff)<<16) | (sign<<31); // whole part and sign
p |= (uint32_t)(((f - (int)f) * 65536.0f))&0xffff; // fraction
return p;
}
float ntohf(uint32_t p)
{
float f = ((p>>16)&0x7fff); // whole part
f += (p&0xffff) / 65536.0f; // fraction
if (((p>>31)&0x1) == 0x1) { f = -f; } // sign bit set
return f;
}
我是否应该在发送之前htonf
通过标准运行打包的浮点数(即的结果)htons
?如果没有,为什么不呢?
据我所知,Beej没有提到这一点。我要问的原因是,如果数据在发送之前未转换为网络字节顺序,则我无法理解接收机器如何可靠地重建将uint32_t
要传递给的s ntohf
(“拆包器”)。
是的,您还必须按定义的顺序整理数据;最简单的方法是使用htonl
。
但是,除了教育目的之外,我真的建议不要使用此代码。它的范围非常有限,并且无声地破坏了大多数数字。而且,它的工作确实不必要地复杂。您也可以将浮点数乘以65536,然后将其强制转换为int发送;转换为浮点数并除以65536.0即可接收。(正如评论中指出的那样,指南的代码是否具有教育意义甚至值得怀疑:我认为这是有教育意义的,因为对其进行批判和/或将其与良好的代码进行比较会教给您一些东西:如果没有别的,那不是网络上所有闪闪发光的东西都是金子。)
这些天实际上几乎所有的CPU都使用IEEE-754格式的float,但是我不会使用Beej的第二种解决方案,因为它的速度不必要地慢。标准库功能frexp
,ldexp
并将可靠地在双精度和相应的尾数以及整数二进制指数之间进行转换。或者,如果您喜欢该界面,可以使用ilogb*
和scalb*
。你可以找到在主机上的尾数通过宏合适的位长FLT_MANT_DIG
,DBL_MANT_DIG
和LDBL_MANT_DIG
(中float.h
)。[见注1]
正确编码浮点数据传输是开始了解浮点表示形式的好方法,这绝对是值得的。但是,如果您只是想通过网络传输浮点数,并且没有要支持的特殊处理器,我建议您仅将浮点数的原始位或双精度字节发送为4字节或8字节整数( (以您选择的字节顺序为标准),并将自己限制为IEEE-754 32位和64位表示形式。
笔记:
frexp
返回的尾数在0.5到1.0之间,但是您真正想要的是整数,因此您应该将尾数按2的正确幂进行缩放,然后从所返回的二进制指数中减去该尾数frexp
。其结果是不是真的精度依赖,只要你可以发送任意精度的整数,所以你并不需要区分float
,double
或者一些其他的二进制表示。本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句