【问题标题】:Convert float to uint8 buffer将浮点数转换为 uint8 缓冲区
【发布时间】:2021-05-11 23:08:55
【问题描述】:

A 有一个 float 变量,我需要将它的值作为字符存储在 uint8 缓冲区中。更准确地说,给定这样的东西

float f = 123.45
uint8_t buffer[11];
memset(buffer, 0x30, sizeof(buffer));   // I set it at 0x30 because it is character '0' 

鉴于此示例,我的缓冲区需要获取值:

0x30 0x30 0x30 0x30 0x30 0x31 0x32 0x33 0x2E 0x34 0x35   // 0x2E is the character '.'

不幸的是,我需要以这种方式将其与现有功能集成,因此无法绕过 11 缓冲区的大小。

任何有关如何解决此问题的建议将不胜感激。

【问题讨论】:

  • 浮点数的十进制文本表示可以使用*printf系列函数获得,例如snprintf
  • 我将它设置为 0x30,因为它是字符 '0' 不,不是。字符'0' 是字符'0'。使用0x30 只会让事情变得混乱。
  • @Andrew Henle,他们正在解释为什么 0x30 被使用而不是 0。 /// @andrei filip,Andrew 的意思是 '0' 更清晰,并且 100% 等同于 0x30(好吧,除非您使用的是 EBCDIC 系统)。
  • 鉴于这是一个嵌入式系统,因此可能资源受限,您不能使用stdio.h 函数。根据您的 MCU 是否真的有 FPU,首先使用浮点可能没有意义。那么,更具体地说,这是针对什么系统?
  • @andreifilip 好的,那么它的 Cortex M0+ 相当受限。你不应该在那个 MCU 上使用软件浮点或stdio.h 函数,它们会吃掉你所有的内存。请相信我在 SO 上的随机 PC 程序员。我自己现在正在使用相同的 MCU,并且我有大约 20 年的嵌入式系统编程经验。而是考虑将浮点数视为原始二进制,然后解析出整数和小数部分,存储在两个整数中,分别将它们转换为 ASCII。这比软件浮点和 stdio.h 的效率高 100 倍左右。

标签: c floating-point type-conversion uint8t


【解决方案1】:

一个简单的方法是:

  1. 为缓冲区分配更多元素(buffer_buffer 此处)
  2. 通过snprintf()将浮点数转换为字符串
  3. 将转换结果复制到buffer
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

int main(void) {
    float f = 123.45;
    uint8_t buffer[11];
    char buffer_buffer[12];
    snprintf(buffer_buffer, sizeof(buffer_buffer), "%011.2f", f);
    memcpy(buffer, buffer_buffer, sizeof(buffer));
    for (int i = 0; i < 11; i++) printf(" 0x%02X", buffer[i]);
    putchar('\n');
    return 0;
}

直接使用snprintf()buffer 效果不佳,因为那里没有终止空字符的空间。

【讨论】:

  • 工作就像一个魅力。谢谢
  • 这是一个 PC 解决方案。 stdio.h 通常从不在(低端)嵌入式系统中使用。
  • "%011.2f" 在处理负数和大正数时会遇到麻烦。
【解决方案2】:

我需要将它的值作为字符存储在 uint8 缓冲区中。

使用sprintf() 和朋友将float 转换为字符串。

诀窍是格式选择。如何将float 的范围和精度容纳在 11 个字节中?

"%f" 对大值失败。对于较小的值,信息会丢失,因为全部变为“0.0”`。

"%e""%g" 解决了 "% .3E" 的范围问题,因为它打印 sd.dddEsee\0",但可能会丢失可能需要更多的精度(例如,常见的 @ 最多 9 个有效数字987654329@)。

"%a" 解决了"% .3A" 的范围问题,因为它打印了0Xsx.xxxPsbb\0,稍微好一点(如果可以丢弃前导“0X”),因为十六进制数字携带更多信息,但指数可能会侵入 3数字。


自适应解决方案。尝试各种进动并返回最好的。 snprintf() 将在 11 字节缓冲区成功时返回 [1...10]。

 char *print_float(size_t sz, char buffer[sz], float f) {
   for (int p = sz - 1; p >= 0; p--)
     int length = snprintf(buffer, sz, "%.*g", p, f);
     if (length > 0 && (unsigned) length < size) {
       return buffer;
     }
   }
   buffer[0] = 0;
   return buffer;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-22
    相关资源
    最近更新 更多