【问题标题】:Parse four bytes to floating-point in C在 C 中将四个字节解析为浮点数
【发布时间】:2009-04-17 03:35:21
【问题描述】:

如何获取四个接收到的数据字节并将它们组合成一个浮点数?

现在我将 bytes 存储在一个数组中,即 received_data[1] ... received_data[4] .我想将这四个 bytes 存储为单个 32 位单精度 float

-谢谢

我实际上收到了一个包含 19 个字节的数据包,并将两组四个字节组合成两个浮点数。所以 received_data[1]received_data[4] 是一个浮点数,received_data[5]received_data[8] strong> 是另一个...

*更新:**** **更多信息...
第一个 bit,或 floatsign 位,是第一个 byte 的第七位,这里是我做了什么检查...

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))  


if( CHECK_BIT(received_data[1], 7))  //set or clear LED2
          {LATAbits.LATA2=1;}else{LATAbits.LATA2=0;}  
if( CHECK_BIT(received_data[5], 7))  //set or clear LED3
          {LATAbits.LATA3=1;}else{LATAbits.LATA3=0;}  

然后我通过从我的数据源发送交替的正数和负数来检查这一点,这应该相应地改变了 LED 并且它起作用了。

只要所有这些都成立,这意味着字节的顺序是正确的,但它们是以小端方式存储的,对吗?这会以正确的顺序存储到浮点数中吗?我还没有运气解析字节并将其作为浮点数读取......

如果有人对此有任何经验,我正在使用 C18 MPLAB IDE 编译器。

最终更新:
我的应用程序正在运行!现在只是一些小错误修复!

谢谢!

感谢大家的帮助!我是 stackoverflow 的新手,但是这里的这个社区真的很棒!像这样的工具真的是无价之宝!我什至无法告诉你你为我节省了多少时间和挫折!

【问题讨论】:

  • 它将是 received_data[0] ... received_data[3]。 0-索引!
  • 我实际上正在接收一个包含 19 个字节的数据包,并将两组四个字节组合成浮点数。所以 received_data[1] 到 received_data[4] 是一个浮点数, received_data[5] 到 received_data[9] 是另一个...

标签: c string parsing floating-point


【解决方案1】:

您需要确保字节顺序正确。要么

float f1 = *(float*)(received_data+1)
float f2 = *(float*)(received_data+5)

或者如果你必须反转字节,你将不得不复制,所以这里有一个替代方案:

union {
  char chars[4];
  float f;
} u;

for (i = 0; i < 4; i++)
  u.chars[3-i] = received_data[i+1];
float f1 = u.f;     
// ... and similarly for second float

最好是这些字节是由类似于此过程的逆过程的东西写入的(或者您将float 的地址转换为char *,或者您有一个char[4] 的联合和'浮动'。)

【讨论】:

  • 当然,验证工会在您的平台上是否有效。我相信这种使用是实现定义的行为,这意味着它允许在某些实现上不起作用,但他们必须这么说。如果它有效,那么它几乎肯定是正确的方法,因为它允许轻松处理字节顺序,并且不鼓励直接在线路上使用结构。如果您采用指针转换路线,您可能需要验证您的 CPU 是否允许未对齐的指针。
  • @RBerteig:我很好奇为什么它是实现定义的。你能解释一下吗?
  • @dreamlax:在某些硬件架构上,由于对齐或其他限制,值可能不直接重叠或根本不重叠。这是不太可能的,但不应该依赖它,除非知道平台允许它并且值确实重叠。
  • 我相信它实际上是 undefined 行为来引用不是最后一个分配给的工会成员。没有关于它的实现定义。但是,根据我自己的违反别名规则的回答,只要您确认目标平台按预期运行(并且您不需要进一步检查即可移植您的代码),那么使用这些是安全的。
【解决方案2】:

通过 memcpy 复制数据怎么样?

inline float FloatFromByteArray (const unsigned char * received_data)
{
  float f;
  memcpy (&f, received_data, sizeof (float));
  return f;
}

它复制从 received_data[0] 开始的数据。如果你想从 received_data[1] 复制,只需在 memcpy 中添加偏移量。

inline float FloatFromByteArray (const unsigned char * received_data)
{
  float f;
  memcpy (&f, received_data+1, sizeof (float));
  return f;
}

【讨论】:

    【解决方案3】:

    您可以按照您机器的endianness 的顺序组装它们,然后转换为float*,并使用该指针访问它们。

    您通常会将它们放在data[0]...data[3] 中。所以...

    char *data;
    
    //Assemble in the *right* order
    data[0] = received_data[4]; // index is machine dependant!
    ...
    
    // cast
    float *fptr = (float *)data;
    printf ("%f\n",*fptr);
    

    根据您的编辑,也许您应该将这些内容转储到struct

    struct packet_s {
       char byte0;
       float f1;
       float f2;
       ...
    }
    

    然后只需 read (2) 或直接进入结构。这种方法之前已经在 SO 上讨论过。例如:

    【讨论】:

    • 这行得通吗?我认为尾数等使用了一组一致的高端或低端位。这不会导致数据未正确对齐吗?
    • @Dana:哪一个? struct dump 方法确实对字节序做出了一些假设......顶部的位允许您修复它。
    • 没关系,我忘了浮点数实际上是 32 位而不是更大的:-\
    【解决方案4】:

    这就是我缓冲浮点数的方式:

    static char* bufferFloat    (int* bLen, float value) {
    *bLen = sizeof(float);
    char* buf = malloc (*bLen);
    int storage;
    
    memcpy (&storage, &value, sizeof (int));
    uint32_t val = htonl (storage);
    memcpy (buf, &val, *bLen);
    
    return buf;
    }
    

    这就是我收到浮点数的方式:

    static float readFloat (char* buf, int* bLen) {
    float ret;
    int temp;
    
    if (*bLen < sizeof (float)) {
        *bLen = 0;
        return 0.0f;
    }
    
    memcpy (&temp, buf, sizeof (int));
    uint32_t val = htonl(temp);
    memcpy (&ret, &val, sizeof (float));
    *bLen = sizeof (float);
    
    return ret;
    }
    

    这是我编写的一些爱好网络代码的一部分。我希望它有所帮助,而且它似乎对我很有效。 :D

    实际上,如果您想要该网络代码,请访问此处:http://cgi.cse.unsw.edu.au/~robertm/myProjects.php 并找到合适的项目。

    【讨论】:

    • 我想它可以工作,但是使用 memcpy() 来处理 4 字节的值似乎是巨大的开销。与 malloc(): 相同的数量一样,您可能需要重新考虑缓冲区管理。
    • 是的,如果您查看我提供的链接,我的方法可能更有意义。
    【解决方案5】:

    假设它们的格式已经正确:

    float f = *((float*)(&received_data[1]));
    

    确保您不是指received_data[0]。如果您有填充字节,我将其保留为一个。

    【讨论】:

    • 打破了 C 别名规则,可能不适用于所有编译,以后可能会变成一个很难找到的错误。
    • 事实上,我们正在处理大多数系统中不存在的类型,这可能无论如何都会将可移植性问题抛到脑后。
    • ISO 添加了严格的别名作为不知道自己在做什么的人的拐杖,IMNSHO。我认为没有理由浪费 CPU 周期来执行具有完全相同的问题的 memcpy() 应该防止别名(可能不兼容的类型)。
    • 我更喜欢使用无严格别名运行。如果我想像婴儿一样被对待,我会在 VB 中编码 :-) [向所有那些 VB 编码员道歉]。
    猜你喜欢
    • 2011-06-16
    • 1970-01-01
    • 2021-06-30
    • 2016-12-26
    • 2022-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-15
    相关资源
    最近更新 更多