c - 在发送之前是否应该通过 htons 运行一个自定义的 float 表示形式?

标签 c sockets networking serialization

我最近喜欢阅读 Beej's Guide to Network Programming .在 section 7.4他谈到了与发送花车有关的问题。他提供了一个简单(天真的)解决方案,他通过将 float 转换为 uint32_t 来“打包” float :

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;
}

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

据我所知,Beej 没有提到这一点。我问的原因是我无法理解如果数据在发送前未转换为网络字节顺序。

最佳答案

是的,您还必须按定义的顺序整理数据;最简单的方法是使用 htonl

但是,除了教育目的之外,我真的建议远离此代码。它的范围非常有限,并且悄悄地破坏了大多数数字。此外,它的功能确实不必要地复杂。您也可以将 float 乘以 65536 并将其转换为 int 以发送;转换为 float 并除以 65536.0 以接收。 (正如评论中所指出的,指南的代码是否具有教育意义甚至值得怀疑:我会说它具有教育意义,因为批评它和/或将它与好的代码进行比较会教给你一些东西:如果没有别的,那不是网络上闪闪发光的一切都是金子。)

现在几乎所有的 CPU 都使用 IEEE-754 格式的 float ,但我也不会使用 Beej 的第二种解决方案,因为它太慢了;标准库函数 frexpldexp 将可靠地在 double 与相应的尾数和整数二进制指数之间进行转换。或者您可以使用 ilogb*scalb*,如果您更喜欢该界面。您可以通过宏 FLT_MANT_DIGDBL_MANT_DIGLDBL_MANT_DIG(在 float. h). [见注1]

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


注意事项:

  1. 实现提示:frexp 返回一个介于 0.5 和 1.0 之间的尾数,但您真正想要的是一个整数,因此您应该按 2 的正确次方缩放尾数并从二进制指数中减去它由 frexp 返回。只要您可以传输任意精度整数,结果就不是真正依赖于精度的,因此您不需要区分 floatdouble 或其他一些二进制表示.

关于c - 在发送之前是否应该通过 htons 运行一个自定义的 float 表示形式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18830302/

相关文章:

c - 非阻塞套接字和io

c - 如何判断eth0模式是static还是dhcp?

c - Unix 域套接字 : Make Latency constant

iphone - 如何在iPhone应用程序编码中使用if-else条件?

c - Arduino 问题 :"' i' 未在此范围内声明”

windows - 如何更改程序的套接字绑定(bind)端口?没有源代码

ruby - 为什么使用Parallel gem运行 “knife solo cook”会给出端口错误?

计算 GFP 载荷 FCS

networking - Rust Alpha 和 Old_IO

c++ - 建立SSL连接并发送GET信息