在发送之前,是否应该通过htons运行float的自定义int表示?

Ras*_*sen 3 c sockets networking serialization

我最近喜欢阅读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;
}
Run Code Online (Sandbox Code Playgroud)

我是否应该在发送之前htonf通过标准运行打包浮动(即结果)htons?如果不是,为什么不呢?

就我所知,Beej并没有提到这一点.我问的原因是,如果数据在发送之前没有转换为网络字节顺序,我无法理解接收机器如何可靠地重建uint32_t要传递给的ntohf("解包器").

ric*_*ici 5

是的,您还必须按照定义的顺序对数据进行编组; 最简单的方法就是使用htonl.

但是,除了教育目的,我还是建议远离这段代码.它的范围非常有限,并且会默默地破坏大多数数字.而且,它的功能确实不必要地复杂化.您也可以将浮点数乘以65536并将其转换为要发送的int; 施放到浮点并除以65536.0接收.(正如评论中所指出的那样,指南的代码是否具有教育性甚至是值得怀疑的:我认为它是教育性的,批评它和/或将它与优秀的代码进行比较会教会你一些东西:如果没有别的,那就不是在网上闪闪发光的一切都是黄金.)

现在几乎所有CPU都在那里使用IEEE-754格式浮点数,但我不会使用Beej的第二个解决方案,因为它不必要地慢; 标准库函数frexpldexp将可靠的双重和相应的尾数和整数二进制指数之间进行转换.或者你可以使用ilogb*scalb*,如果你喜欢的界面.你可以找到在主机上的尾数通过宏合适的位长FLT_MANT_DIG,DBL_MANT_DIGLDBL_MANT_DIG(中float.h).[见注1]

正确编码浮点数据传输是开始理解浮点表示的好方法,这绝对是值得的.但是如果你只是想通过线路传输浮点数并且你没有一些特殊的处理器来支持,我建议只发送float或double的原始位作为4字节或8字节整数(以您选择的任何字节顺序作为标准,并限制自己使用IEEE-754 32位和64位表示.


笔记:

  1. 实现提示:frexp返回0.5和1.0之间的尾数,但你真正想要的是一个整数,所以你应该用正确的2的幂来缩放尾数,并从返回的二进制指数中减去它frexp.其结果是不是真的精度依赖,只要你可以发送任意精度的整数,所以你并不需要区分float,double或者一些其他的二进制表示.